mirror of
https://github.com/kmein/niveum
synced 2026-03-19 11:31:09 +01:00
chore: move configs to system directories
This commit is contained in:
@@ -1,57 +0,0 @@
|
||||
{ pkgs, lib, ... }:
|
||||
let
|
||||
inherit (import <niveum/lib>) serveHtml;
|
||||
stations = [
|
||||
900068204 # A/M
|
||||
900068302 # KAS
|
||||
900068203 # B-P
|
||||
];
|
||||
fahrplan = pkgs.writeText "fahrplan.html" ''
|
||||
<!DOCTYPE html>
|
||||
<title>Fahrplan</title>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/x-icon"
|
||||
href="https://mobil.bvg.de/Fahrinfo/img/ua_xhtml/logo.gif"
|
||||
/>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
--bvg-yellow: #f0d722;
|
||||
}
|
||||
#fahrplan {
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
flex-direction: row;
|
||||
}
|
||||
#fahrplan iframe {
|
||||
flex-grow: 1;
|
||||
border: none;
|
||||
}
|
||||
#fahrplan iframe + iframe {
|
||||
border-left: 2px solid var(--bvg-yellow);
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<div id="fahrplan">
|
||||
${lib.concatMapStrings (station: ''
|
||||
<iframe scrolling="no" src="https://mobil.bvg.de/Fahrinfo/bin/stboard.bin/dox?ld=0.1&input=${toString station}&boardType=depRT&start=yes"></iframe>
|
||||
'') stations}
|
||||
</div>
|
||||
</body>
|
||||
'';
|
||||
in
|
||||
{
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
recommendedGzipSettings = true;
|
||||
recommendedOptimisation = true;
|
||||
recommendedProxySettings = true;
|
||||
recommendedTlsSettings = true;
|
||||
};
|
||||
|
||||
services.nginx.virtualHosts."bvg.kmein.r" = {
|
||||
locations."/".extraConfig = serveHtml fahrplan pkgs;
|
||||
};
|
||||
}
|
||||
@@ -20,16 +20,12 @@ in {
|
||||
config = {
|
||||
allowUnfree = true;
|
||||
packageOverrides = pkgs: {
|
||||
writeDashBin = pkgs.writers.writeDashBin;
|
||||
writeDash = pkgs.writers.writeDash;
|
||||
gfs-fonts = pkgs.callPackage <niveum/packages/gfs-fonts.nix> {};
|
||||
iolanguage = pkgs.callPackage <niveum/packages/iolanguage.nix> { };
|
||||
ix = pkgs.callPackage <niveum/packages/ix.nix> { };
|
||||
};
|
||||
};
|
||||
overlays = [
|
||||
(import <nix-writers/pkgs>)
|
||||
(import <stockholm/krebs/5pkgs>)
|
||||
(self: super: {
|
||||
scripts = import <niveum/packages/scripts> { pkgs = super; lib = super.lib; };
|
||||
})
|
||||
@@ -201,7 +197,6 @@ in {
|
||||
./beets.nix
|
||||
./bluetooth.nix
|
||||
./ccc.nix
|
||||
# ./kleiter.nix
|
||||
./khal.nix
|
||||
./engiadina.nix
|
||||
./chromium.nix
|
||||
@@ -215,7 +210,6 @@ in {
|
||||
./flix.nix
|
||||
./fonts.nix
|
||||
./fzf.nix
|
||||
./gaslight.nix
|
||||
./git.nix
|
||||
./hledger.nix
|
||||
./htop.nix
|
||||
@@ -225,7 +219,6 @@ in {
|
||||
./lb.nix
|
||||
./mpv.nix
|
||||
./mime.nix
|
||||
./nano.nix
|
||||
./neovim.nix
|
||||
./neomutt.nix
|
||||
./nix.nix
|
||||
@@ -247,7 +240,6 @@ in {
|
||||
./sxiv.nix
|
||||
./theming.nix
|
||||
./tmux.nix
|
||||
# ./tor.nix
|
||||
./traadfri.nix
|
||||
./unclutter.nix
|
||||
./version.nix
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
environment.systemPackages = [
|
||||
(pkgs.writers.writeDashBin "gaslight-stream" ''
|
||||
${pkgs.ffmpeg}/bin/ffmpeg -r 14 -s 640x480 -f video4linux2 -i /dev/video0 -f alsa -i default -c:v libx264 -preset ultrafast -c:a aac -f avi -
|
||||
'')
|
||||
(pkgs.writers.writeDashBin "gaslight-say" ''
|
||||
voices="de
|
||||
de+whisper"
|
||||
|
||||
echo "$@" | ${pkgs.espeak}/bin/espeak -v "$(echo "$voices" | ${pkgs.coreutils}/bin/shuf -n1)"
|
||||
'')
|
||||
(pkgs.writers.writeDashBin "gaslight-play" ''
|
||||
set -o noglob
|
||||
${pkgs.mpv}/bin/mpv --no-video "$1"
|
||||
'')
|
||||
];
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
ssh machine gaslight-stream | mpv -
|
||||
ssh machine gaslight-say "blablabla"
|
||||
|
||||
*/
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
services.gitea = {
|
||||
enable = true;
|
||||
disableRegistration = true;
|
||||
rootUrl = "https://code.kmein.de";
|
||||
appName = "code.kmein.de";
|
||||
};
|
||||
services.nginx.virtualHosts."code.kmein.de" = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
locations."/".extraConfig = "proxy_pass http://localhost:3000;";
|
||||
};
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
let
|
||||
inherit (import ./lib.nix) triggers;
|
||||
inherit (import <niveum/lib>) localAddresses;
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
./zigbee.nix
|
||||
./frontend.nix
|
||||
];
|
||||
|
||||
services.home-assistant = {
|
||||
enable = true;
|
||||
configWritable = true;
|
||||
lovelaceConfigWritable = true;
|
||||
openFirewall = true;
|
||||
config = {
|
||||
homeassistant = {
|
||||
name = "Toum";
|
||||
latitude = config.location.latitude;
|
||||
longitude = config.location.longitude;
|
||||
elevation = 90; # TODO find out how high I live
|
||||
unit_system = "metric";
|
||||
time_zone = config.time.timeZone;
|
||||
};
|
||||
config = {};
|
||||
discovery = {};
|
||||
system_health = {};
|
||||
history = {};
|
||||
# tradfri.host = localAddresses.tradfri; # dont use until python3Packages.pytradfri is packaged
|
||||
sun = {};
|
||||
mobile_app = {};
|
||||
shopping_list = {};
|
||||
sensor = [
|
||||
{
|
||||
platform = "dwd_weather_warnings";
|
||||
region_name = "Berlin";
|
||||
}
|
||||
];
|
||||
mqtt = {
|
||||
broker = "localhost";
|
||||
port = 1883;
|
||||
client_id = "home-assistant";
|
||||
username = "albrecht";
|
||||
password = lib.strings.fileContents <system-secrets/mosquitto>;
|
||||
keepalive = 60;
|
||||
protocol = "3.1";
|
||||
|
||||
discovery = true;
|
||||
birth_message = {
|
||||
topic = "/hass/status";
|
||||
payload = "online";
|
||||
};
|
||||
will_message = {
|
||||
topic = "/hass/status";
|
||||
payload = "offline";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
let
|
||||
inherit (import ./lib.nix) triggers;
|
||||
in
|
||||
{
|
||||
services.home-assistant.config = {
|
||||
frontend = {
|
||||
themes = {
|
||||
day_theme = import ./themes/clear.nix;
|
||||
night_theme = import ./themes/clear-dark.nix;
|
||||
};
|
||||
};
|
||||
automation = [
|
||||
{
|
||||
alias = "Night Theme";
|
||||
hide_entity = true;
|
||||
trigger = triggers.night;
|
||||
action = [
|
||||
{
|
||||
service = "frontend.set_theme";
|
||||
data.name = "night_theme";
|
||||
}
|
||||
];
|
||||
}
|
||||
{
|
||||
alias = "Day Theme";
|
||||
hide_entity = true;
|
||||
trigger = triggers.day;
|
||||
action = [
|
||||
{
|
||||
service = "frontend.set_theme";
|
||||
data.name = "day_theme";
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
{
|
||||
triggers = {
|
||||
night = {
|
||||
platform = "numeric_state";
|
||||
entity_id = "sun.sun";
|
||||
value_template = "{{ state.attributes.elevation }}";
|
||||
below = -4.0;
|
||||
};
|
||||
day = {
|
||||
platform = "numeric_state";
|
||||
entity_id = "sun.sun";
|
||||
value_template = "{{ state.attributes.elevation }}";
|
||||
above = 0;
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
rec {
|
||||
# Colors
|
||||
text-color = "#DADADB"; # Grey text
|
||||
text-medium-light-color = "#A0A2A8"; # Medium-light grey text
|
||||
text-medium-color = "#80828A"; # Medium grey text
|
||||
text-dark-color = "#6A6B74"; # Dark grey text
|
||||
accent-color = "#008bef"; # Blue
|
||||
accent-medium-color = "#2484C9"; # Decent blue
|
||||
background-color = "#3b4049"; # Dark grey background
|
||||
background-color-2 = "#484E59"; # Light grey background
|
||||
background-card-color = "#434952"; # Grey background
|
||||
border-color = "#383C46"; # Grey border
|
||||
|
||||
# Header
|
||||
app-header-background-color = "#363941"; # Background color
|
||||
|
||||
# Text
|
||||
primary-color = text-color;
|
||||
text-primary-color = text-color;
|
||||
|
||||
# Left Menu
|
||||
paper-listbox-background-color = background-color; # Background
|
||||
sidebar-icon-color = text-medium-color; # icons
|
||||
sidebar-selected-icon-color = text-medium-light-color; # Selected row icon and background (15%)
|
||||
sidebar-selected-text-color = text-color; # Selected row label
|
||||
|
||||
# UI
|
||||
paper-card-header-color = text-color; # Title in settings
|
||||
primary-background-color = background-color; # Background (also title background in left menu)
|
||||
mdc-theme-primary = accent-medium-color; # Action Buttons (save, restart etc.)
|
||||
card-background-color = background-card-color; # Entity Registry Background
|
||||
|
||||
# Card
|
||||
paper-card-background-color = background-card-color; # Background
|
||||
dark-primary-color = text-color;
|
||||
primary-text-color = text-color;
|
||||
paper-listbox-color = text-color;
|
||||
light-primary-color = text-dark-color;
|
||||
secondary-text-color = text-medium-color;
|
||||
disabled-text-color = text-dark-color;
|
||||
paper-dialog-button-color = text-color;
|
||||
secondary-background-color = background-color-2; # Background more info title
|
||||
|
||||
# Icons
|
||||
paper-item-icon-color = text-dark-color; # Off
|
||||
paper-item-icon-active-color = accent-color; # On
|
||||
|
||||
# Switches
|
||||
switch-checked-button-color = text-medium-light-color; # Knob On
|
||||
switch-unchecked-button-color = text-medium-light-color; # Knob Off
|
||||
switch-checked-track-color = "#009FFF"; # Background On
|
||||
switch-unchecked-track-color = "#767682"; # Background Off
|
||||
|
||||
# Slider
|
||||
paper-slider-active-color = accent-color; # Line On
|
||||
paper-slider-knob-color = text-medium-light-color; # Knob On
|
||||
paper-slider-container-color = text-dark-color; # Line Off
|
||||
paper-slider-knob-start-color = text-medium-light-color; # Knob Off
|
||||
|
||||
# Badges
|
||||
label-badge-text-color = text-color;
|
||||
label-badge-background-color = "rgba(54, 57, 65, 0.6)";
|
||||
|
||||
# Shadows
|
||||
ha-card-box-shadow = "inset 0px 0px 0px 1px var(--border-color)";
|
||||
|
||||
# HACS
|
||||
hacs-badge-color = accent-color; # New Badge
|
||||
hacs-status-installed = text-color; # Installed Icon
|
||||
hacs-status-pending-restart = text-dark-color; # Restart Icon
|
||||
hacs-status-pending-update = accent-color;
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
rec {
|
||||
text-color = "#636B75"; # Grey text
|
||||
text-medium-color = "#8c96a5"; # Medium grey text
|
||||
text-light-color = "#BAC0C6"; # Light grey text
|
||||
accent-color = "#00a1ff"; # Blue
|
||||
background-color = "#F7F8F9"; # Light grey background
|
||||
background-color-2 = "#F4F5F6"; # Light grey background
|
||||
background-card-color = "rgba(255,255,255,1.0)"; # White background
|
||||
border-color = "#E8E8E8"; # Light grey border
|
||||
|
||||
# Header
|
||||
primary-color = text-color; # Background
|
||||
text-primary-color = "#FFF"; # Text
|
||||
|
||||
# Left Menu
|
||||
paper-listbox-background-color = background-color; # Background
|
||||
# TODO = Text and Icons
|
||||
|
||||
# UI
|
||||
paper-card-header-color = text-color; # Title in settings
|
||||
primary-background-color = background-color; # Background color (also title background in left menu)
|
||||
|
||||
# Card
|
||||
paper-card-background-color = background-card-color; # Background
|
||||
dark-primary-color = text-color;
|
||||
primary-text-color = text-color;
|
||||
paper-listbox-color = text-color;
|
||||
light-primary-color = text-light-color;
|
||||
secondary-text-color = text-medium-color;
|
||||
disabled-text-color = text-light-color;
|
||||
paper-dialog-button-color = text-color;
|
||||
secondary-background-color = background-color-2; # Background more info title
|
||||
|
||||
# Icons
|
||||
paper-item-icon-color = text-light-color; # Off
|
||||
paper-item-icon-active-color = accent-color; # On
|
||||
|
||||
# Switches
|
||||
switch-checked-button-color = "#FFF"; # Knob On
|
||||
switch-unchecked-button-color = "#FFF"; # Knob Off
|
||||
switch-checked-track-color = "#0077FF"; # Background On
|
||||
switch-unchecked-track-color = disabled-text-color; # Background Off
|
||||
|
||||
# Slider
|
||||
paper-slider-active-color = accent-color; # Line On
|
||||
paper-slider-container-color = "#e5e7ea"; # Line Off
|
||||
paper-slider-knob-color = text-light-color; # Knob On
|
||||
paper-slider-knob-start-color = text-light-color; # Knob Off
|
||||
|
||||
# Shadows
|
||||
ha-card-box-shadow = "inset 0px 0px 0px 1px var(--border-color)";
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
let
|
||||
inherit (import <niveum/lib>) localAddresses;
|
||||
in
|
||||
{
|
||||
services.zigbee2mqtt = {
|
||||
enable = true;
|
||||
config = {
|
||||
permit_join = false;
|
||||
homeassistant = true;
|
||||
serial = {
|
||||
port = "/dev/ttyACM0";
|
||||
disable_led = true;
|
||||
};
|
||||
mqtt = {
|
||||
discovery = true;
|
||||
base_topic = "zigbee";
|
||||
server = "mqtt://${localAddresses.toum}";
|
||||
user = "albrecht";
|
||||
password = lib.strings.fileContents <system-secrets/mosquitto>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
services.mosquitto = {
|
||||
enable = true;
|
||||
host = "0.0.0.0";
|
||||
allowAnonymous = false;
|
||||
checkPasswords = true;
|
||||
users."albrecht" = {
|
||||
password = lib.strings.fileContents <system-secrets/mosquitto>;
|
||||
acl = [ "topic readwrite #" ];
|
||||
};
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [ 1883 ];
|
||||
|
||||
environment.systemPackages = [ pkgs.mosquitto ];
|
||||
|
||||
services.home-assistant = {
|
||||
config = {
|
||||
switch = [
|
||||
{
|
||||
platform = "mqtt";
|
||||
name = "zigbee2mqtt_join";
|
||||
state_topic = "/zigbee2mqtt/bridge/config/permit_join";
|
||||
command_topic = "/zigbee2mqtt/bridge/config/permit_join";
|
||||
payload_on = "true";
|
||||
payload_off = "false";
|
||||
}
|
||||
];
|
||||
timer.zigbee_permit_join = {
|
||||
name = "Zigbee Time remaining";
|
||||
duration = 120;
|
||||
};
|
||||
automation = [
|
||||
# Automation to start timer when enable join is turned on
|
||||
{
|
||||
id = "zigbee_join_enabled";
|
||||
alias = "";
|
||||
hide_entity = "true";
|
||||
trigger = {
|
||||
platform = "state";
|
||||
entity_id = "switch.zigbee2mqtt_join";
|
||||
to = "on";
|
||||
};
|
||||
action = {
|
||||
service = "timer.start";
|
||||
entity_id = "timer.zigbee_permit_join";
|
||||
};
|
||||
}
|
||||
# Automation to stop timer when switch turned off and turn off switch when timer finished
|
||||
{
|
||||
id = "zigbee_join_disabled";
|
||||
hide_entity = "true";
|
||||
trigger = [
|
||||
{
|
||||
platform = "event";
|
||||
event_type = "timer.finished";
|
||||
event_data.entity_id = "timer.zigbee_permit_join";
|
||||
}
|
||||
{
|
||||
platform = "state";
|
||||
entity_id = "switch.zigbee2mqtt_join";
|
||||
to = "off";
|
||||
}
|
||||
];
|
||||
action = [
|
||||
{
|
||||
service = "timer.cancel";
|
||||
data.entity_id = "timer.zigbee_permit_join";
|
||||
}
|
||||
{
|
||||
service = "switch.turn_off";
|
||||
entity_id = "switch.zigbee2mqtt_join";
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
{ config, pkgs, ... }:
|
||||
let
|
||||
backupLocation = "/var/lib/codimd-backup";
|
||||
stateLocation = "/var/lib/codimd/state.sqlite";
|
||||
nixpkgs-unstable = import <nixpkgs-unstable> {};
|
||||
domain = "pad.kmein.de";
|
||||
in
|
||||
{
|
||||
imports = [ <stockholm/krebs/3modules/permown.nix> ];
|
||||
|
||||
services.nginx.virtualHosts.${domain} = {
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
locations."/" = {
|
||||
proxyPass = "https://localhost:3091";
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
};
|
||||
|
||||
security.acme.certs.${domain}.group = "hedgecert";
|
||||
users.groups.hedgecert.members = [ "codimd" "nginx" ];
|
||||
|
||||
security.dhparams = {
|
||||
enable = true;
|
||||
params.hedgedoc = {};
|
||||
};
|
||||
|
||||
services.hedgedoc = {
|
||||
enable = true;
|
||||
configuration = {
|
||||
allowOrigin = [ domain ];
|
||||
allowAnonymous = true;
|
||||
allowGravatar = false;
|
||||
allowFreeURL = true;
|
||||
db = {
|
||||
dialect = "sqlite";
|
||||
storage = stateLocation;
|
||||
};
|
||||
port = 3091;
|
||||
domain = domain;
|
||||
useSSL = true;
|
||||
protocolUseSSL = true;
|
||||
sslCAPath = [ "/etc/ssl/certs/ca-certificates.crt" ];
|
||||
sslCertPath = "/var/lib/acme/${domain}/cert.pem";
|
||||
sslKeyPath = "/var/lib/acme/${domain}/key.pem";
|
||||
dhParamPath = config.security.dhparams.params.hedgedoc.path;
|
||||
};
|
||||
};
|
||||
|
||||
krebs.permown.${backupLocation} = { owner = "codimd"; group = "codimd"; umask = "0002"; };
|
||||
|
||||
systemd.services.hedgedoc-backup = {
|
||||
description = "Hedgedoc backup service";
|
||||
script = ''
|
||||
${nixpkgs-unstable.sqlite}/bin/sqlite3 -json ${stateLocation} "select shortid, alias, ownerId, content from Notes" \
|
||||
| ${pkgs.writers.writePython3 "hedgedoc-json-to-fs.py" {} ''
|
||||
import json
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
for note in json.load(sys.stdin):
|
||||
user_directory = pathlib.Path()
|
||||
if note["ownerId"]:
|
||||
user_directory = pathlib.Path(note["ownerId"])
|
||||
user_directory.mkdir(exist_ok=True)
|
||||
file_path = user_directory / (
|
||||
(note["alias"] if note["alias"] else note["shortid"]) + ".md"
|
||||
)
|
||||
file_path.write_text(note["content"])
|
||||
print(f"✔ {file_path}", file=sys.stderr)
|
||||
''}
|
||||
'';
|
||||
startAt = "hourly";
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
User = "codimd";
|
||||
Group = "codimd";
|
||||
WorkingDirectory = backupLocation;
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
{ pkgs, lib, ... }:
|
||||
{
|
||||
nixpkgs.overlays = [
|
||||
(self: super: {
|
||||
matterbridge = (import (super.fetchFromGitHub {
|
||||
owner = "NixOS";
|
||||
repo = "nixpkgs";
|
||||
rev = "e45d91ee65db293a172ec506759d1248e40c35f5";
|
||||
sha256 = "03cjs5xcx09lw0djyrx2kfakw7gkg4iqmy9w25azai62im39l30k";
|
||||
}) {}).matterbridge;
|
||||
})
|
||||
];
|
||||
|
||||
services.matterbridge = {
|
||||
enable = true;
|
||||
configPath =
|
||||
let bridgeBotToken = lib.strings.fileContents <system-secrets/telegram/kmein.token>;
|
||||
in toString ((pkgs.formats.toml {}).generate "config.toml" {
|
||||
general = {
|
||||
RemoteNickFormat = "[{NICK}] ";
|
||||
Charset = "utf-8";
|
||||
};
|
||||
telegram.kmein.Token = bridgeBotToken;
|
||||
irc =
|
||||
let Nick = "ponte";
|
||||
in {
|
||||
hackint = { Server = "irc.hackint.org:6697"; UseTLS = true; inherit Nick; };
|
||||
};
|
||||
mumble.lassulus = {
|
||||
Server = "lassul.us:64738";
|
||||
Nick = "krebs_bridge";
|
||||
SkipTLSVerify = true;
|
||||
};
|
||||
gateway = [
|
||||
{
|
||||
name = "krebs-bridge";
|
||||
enable = true;
|
||||
inout = [
|
||||
{
|
||||
account = "irc.hackint";
|
||||
channel = "#krebs";
|
||||
}
|
||||
{
|
||||
account = "telegram.kmein";
|
||||
channel = "-330372458";
|
||||
}
|
||||
{
|
||||
account = "mumble.lassulus";
|
||||
channel = 6; # "nixos"
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
});
|
||||
};
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
{ pkgs, lib, ... }:
|
||||
let
|
||||
backend = pkgs.callPackage <niveum/submodules/menstruation-backend> {};
|
||||
telegram = pkgs.callPackage <niveum/submodules/menstruation-telegram> {};
|
||||
backendPort = 8000;
|
||||
in
|
||||
{
|
||||
containers.menstruation.autoStart = true;
|
||||
containers.menstruation.config = { config, pkgs, ... }: {
|
||||
services.redis.enable = true;
|
||||
|
||||
systemd.services.menstruation-telegram = {
|
||||
wants = [
|
||||
"network-online.target"
|
||||
"menstruation-backend.service"
|
||||
"redis.service"
|
||||
];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
environment = {
|
||||
MENSTRUATION_TOKEN = lib.strings.fileContents <system-secrets/telegram/menstruation.token>;
|
||||
MENSTRUATION_ENDPOINT = "http://localhost:${toString backendPort}";
|
||||
MENSTRUATION_MODERATORS = "18980945";
|
||||
};
|
||||
serviceConfig = {
|
||||
Restart = "always";
|
||||
DynamicUser = true;
|
||||
ExecStart = "${telegram}/bin/menstruation-telegram";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.menstruation-backend = {
|
||||
wants = [ "network-online.target" ];
|
||||
environment.ROCKET_PORT = toString backendPort;
|
||||
serviceConfig = {
|
||||
Restart = "always";
|
||||
DynamicUser = true;
|
||||
ExecStart = "${backend}/bin/menstruation_server";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
# https://github.com/Fluepke/nix-files/blob/2be70b76a198afaa7763132fed645a3c19d5af6e/configuration/common/blackbox-exporter.yml
|
||||
# https://github.com/xHain-hackspace/xhain-nixfiles/blob/0d6e3b87a07317c2d54cccabf4f90da589319e2c/common/prometheus/blackbox-exporter.yml
|
||||
{
|
||||
modules.http_2xx = {
|
||||
http = {
|
||||
fail_if_not_ssl = true;
|
||||
ip_protocol_fallback = false;
|
||||
method = "GET";
|
||||
no_follow_redirects = false;
|
||||
preferred_ip_protocol = "ip4";
|
||||
valid_http_versions = [ "HTTP/1.1" "HTTP/2.0" ];
|
||||
tls_config.insecure_skip_verify = true;
|
||||
};
|
||||
prober = "http";
|
||||
timeout = "15s";
|
||||
};
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
{
|
||||
auth_enabled = false;
|
||||
server = {
|
||||
http_listen_port = 3100;
|
||||
grpc_listen_port = 9096;
|
||||
};
|
||||
ingester = {
|
||||
wal = {
|
||||
enabled = true;
|
||||
dir = "/tmp/wal";
|
||||
};
|
||||
lifecycler = {
|
||||
address = "127.0.0.1";
|
||||
ring = {
|
||||
kvstore.store = "inmemory";
|
||||
replication_factor = 1;
|
||||
};
|
||||
final_sleep = "0s";
|
||||
};
|
||||
chunk_idle_period = "1h"; # Any chunk not receiving new logs in this time will be flushed
|
||||
max_chunk_age = "1h"; # All chunks will be flushed when they hit this age, default is 1h
|
||||
chunk_target_size = 1048576; # Loki will attempt to build chunks up to 1.5MB, flushing first if chunk_idle_period or max_chunk_age is reached first
|
||||
chunk_retain_period = "30s"; # Must be greater than index read cache TTL if using an index cache (Default index read cache TTL is 5m)
|
||||
max_transfer_retries = 0; # Chunk transfers disabled
|
||||
};
|
||||
schema_config.configs = [
|
||||
{
|
||||
from = "2020-10-24";
|
||||
store = "boltdb-shipper";
|
||||
object_store = "filesystem";
|
||||
schema = "v11";
|
||||
index = {
|
||||
prefix = "index_";
|
||||
period = "24h";
|
||||
};
|
||||
}
|
||||
];
|
||||
storage_config = {
|
||||
boltdb_shipper = {
|
||||
active_index_directory = "/tmp/loki/boltdb-shipper-active";
|
||||
cache_location = "/tmp/loki/boltdb-shipper-cache";
|
||||
cache_ttl = "24h"; # Can be increased for faster performance over longer query periods, uses more disk space
|
||||
shared_store = "filesystem";
|
||||
};
|
||||
filesystem.directory = "/tmp/loki/chunks";
|
||||
};
|
||||
compactor = {
|
||||
working_directory = "/tmp/loki/boltdb-shipper-compactor";
|
||||
shared_store = "filesystem";
|
||||
};
|
||||
limits_config = {
|
||||
reject_old_samples = true;
|
||||
reject_old_samples_max_age = "168h";
|
||||
};
|
||||
chunk_store_config.max_look_back_period = "0s";
|
||||
table_manager = {
|
||||
retention_deletes_enabled = false;
|
||||
retention_period = "0s";
|
||||
};
|
||||
}
|
||||
@@ -1,229 +0,0 @@
|
||||
{ lib, config, pkgs, ... }:
|
||||
let
|
||||
lokiConfig = import ./loki.nix;
|
||||
blackboxConfig = import ./blackbox.nix;
|
||||
in
|
||||
{
|
||||
services.grafana = {
|
||||
enable = true;
|
||||
domain = "grafana.kmein.r";
|
||||
port = 9444;
|
||||
addr = "127.0.0.1";
|
||||
};
|
||||
|
||||
services.nginx.virtualHosts.${config.services.grafana.domain} = {
|
||||
locations."/" = {
|
||||
proxyPass = "http://127.0.0.1:${toString config.services.grafana.port}";
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
};
|
||||
|
||||
services.prometheus.rules = let diskFreeThreshold = 10; in [(builtins.toJSON {
|
||||
groups = [{
|
||||
name = "niveum";
|
||||
rules = [
|
||||
{
|
||||
alert = "ServiceDown";
|
||||
expr = ''node_systemd_unit_state{state="failed"} == 1'';
|
||||
annotations = {
|
||||
summary = "{{$labels.job}}: Service {{$labels.name}} failed to start.";
|
||||
};
|
||||
}
|
||||
{
|
||||
alert = "RootPartitionFull";
|
||||
for = "10m";
|
||||
expr = ''(node_filesystem_free_bytes{mountpoint="/"} * 100) / node_filesystem_size_bytes{mountpoint="/"} < ${toString diskFreeThreshold}'';
|
||||
annotations = {
|
||||
summary = "{{ $labels.job }}: Filesystem is running out of space soon.";
|
||||
description = ''The root disk of {{ $labels.job }} has {{ $value | printf "%.2f" }}% free disk space (threshold at ${toString diskFreeThreshold}%).'';
|
||||
};
|
||||
}
|
||||
{
|
||||
alert = "RootPartitionFullWeek";
|
||||
for = "1h";
|
||||
expr = ''node_filesystem_free_bytes{mountpoint="/"} ''
|
||||
+ ''and predict_linear(node_filesystem_free_bytes{mountpoint="/"}[2d], 7*24*3600) <= 0'';
|
||||
annotations = {
|
||||
summary = "{{$labels.job}}: Filesystem is running out of space in 7 days.";
|
||||
};
|
||||
}
|
||||
{
|
||||
alert = "HighLoad";
|
||||
expr = ''node_load15 / on(job) count(node_cpu_seconds_total{mode="system"}) by (job) >= 1.0'';
|
||||
for = "10m";
|
||||
annotations = {
|
||||
summary = "{{$labels.job}}: Running on high load: {{$value}}";
|
||||
};
|
||||
}
|
||||
{
|
||||
alert = "HighRAM";
|
||||
expr = "node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes < node_memory_MemTotal_bytes * 0.1";
|
||||
for = "1h";
|
||||
annotations.summary = "{{$labels.job}}: Using lots of RAM.";
|
||||
}
|
||||
{
|
||||
alert = "UptimeMonster";
|
||||
expr = "time() - node_boot_time_seconds > 2592000";
|
||||
annotations.summary = "{{$labels.job}}: up for more than 30 days.";
|
||||
}
|
||||
{
|
||||
alert = "HostDown";
|
||||
expr = ''up == 0'';
|
||||
for = "5m";
|
||||
annotations = {
|
||||
summary = "Host {{ $labels.job }} down for 5 minutes.";
|
||||
};
|
||||
}
|
||||
{
|
||||
alert = "Reboot";
|
||||
expr = "time() - node_boot_time_seconds < 300";
|
||||
annotations.summary = "{{$labels.job}}: Reboot";
|
||||
}
|
||||
{
|
||||
alert = "ProbeFailed";
|
||||
expr = "probe_success == 0";
|
||||
for = "5m";
|
||||
annotations.summary = "{{$labels.instance}}: probe failed";
|
||||
}
|
||||
{
|
||||
alert = "SlowProbe";
|
||||
expr = "avg_over_time(probe_http_duration_seconds[1m]) > 1";
|
||||
for = "5m";
|
||||
annotations.summary = "{{$labels.instance}}: HTTP probe slow";
|
||||
}
|
||||
{
|
||||
alert = "HttpStatusCode";
|
||||
expr = "probe_http_status_code != 0 AND (probe_http_status_code <= 199 OR probe_http_status_code >= 400)";
|
||||
for = "5m";
|
||||
annotations.summary = "{{$labels.instance}}: status code {{$value}}";
|
||||
}
|
||||
{
|
||||
alert = "SslExpirySoon";
|
||||
expr = "probe_ssl_earliest_cert_expiry - time() < 86400 * 30";
|
||||
for = "5m";
|
||||
annotations.summary = "{{$labels.instance}}: SSL certificate expires in 30 days";
|
||||
}
|
||||
{
|
||||
alert = "SslExpiry";
|
||||
expr = "probe_ssl_earliest_cert_expiry - time() <= 0";
|
||||
for = "5m";
|
||||
annotations.summary = "{{$labels.instance}}: SSL certificate has expired";
|
||||
}
|
||||
];
|
||||
}];
|
||||
})];
|
||||
|
||||
systemd.services.alertmanager-bot-telegram =
|
||||
let
|
||||
alertmanager-bot-telegram = pkgs.buildGoModule rec {
|
||||
pname = "alertmanager-bot";
|
||||
version = "2020-07-13";
|
||||
src = pkgs.fetchFromGitHub {
|
||||
owner = "metalmatze";
|
||||
repo = "alertmanager-bot";
|
||||
rev = "5efc0bbbf8023d4324e9da98562f064a714a7206";
|
||||
sha256 = "09cciml1j8x76jpm2v5v6h2q6j1fkhsz1kswslmx8wl4wk40xgp4";
|
||||
};
|
||||
vendorSha256 = "1v0fgin8dn81b559zz4lqmrl7hikr46g4gb18sci4riql5qs1isj";
|
||||
postInstall = ''
|
||||
install -D ./default.tmpl $out/templates/default.tmpl
|
||||
'';
|
||||
};
|
||||
in {
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "ip-up.target" ];
|
||||
environment.TELEGRAM_ADMIN = "18980945";
|
||||
environment.TELEGRAM_TOKEN = lib.strings.fileContents <system-secrets/telegram/prometheus.token>;
|
||||
serviceConfig = {
|
||||
DynamicUser = true;
|
||||
StateDirectory = "alertbot";
|
||||
ExecStart = ''${alertmanager-bot-telegram}/bin/alertmanager-bot \
|
||||
--alertmanager.url=http://localhost:9093 --log.level=info \
|
||||
--store=bolt --bolt.path=/var/lib/alertbot/bot.db \
|
||||
--listen.addr="0.0.0.0:16320" \
|
||||
--template.paths=${pkgs.writeText "template.tmpl" ''
|
||||
{{ define "telegram.default" }}
|
||||
{{range .Alerts -}}
|
||||
{{ if eq .Status "firing" }}
|
||||
⚠ <b>{{ index .Annotations "summary"}}</b>
|
||||
{{ index .Annotations "description" }}
|
||||
|
||||
See on Grafana: http://${config.services.grafana.domain}/d/alpUteInz/niveum
|
||||
{{ else -}}
|
||||
RESOLVED 😌 <del>{{ index .Annotations "summary"}}</del>
|
||||
{{- end }}
|
||||
{{end -}}
|
||||
{{end}}
|
||||
''}'';
|
||||
};
|
||||
};
|
||||
|
||||
services.prometheus.alertmanager = {
|
||||
enable = true;
|
||||
listenAddress = "localhost";
|
||||
configuration = {
|
||||
route = {
|
||||
group_wait = "30s";
|
||||
repeat_interval = "4h";
|
||||
receiver = "me";
|
||||
};
|
||||
receivers = [{
|
||||
name = "me";
|
||||
webhook_configs = [{
|
||||
url = "http://localhost:16320";
|
||||
send_resolved = true;
|
||||
}];
|
||||
}];
|
||||
};
|
||||
};
|
||||
|
||||
services.prometheus.alertmanagers = [{
|
||||
scheme = "http";
|
||||
path_prefix = "/";
|
||||
static_configs = [ { targets = [ "localhost:9093" ]; } ];
|
||||
}];
|
||||
|
||||
services.prometheus.scrapeConfigs = [
|
||||
{
|
||||
job_name = "makanek";
|
||||
static_configs = [ { targets = [
|
||||
"127.0.0.1:${toString config.services.prometheus.exporters.node.port}"
|
||||
]; } ];
|
||||
}
|
||||
{
|
||||
scrape_interval = "5m";
|
||||
job_name = "blackbox";
|
||||
metrics_path = "/probe";
|
||||
params.module = [ "http_2xx" ];
|
||||
relabel_configs = [
|
||||
{ source_labels = ["__address__"]; target_label = "__param_target"; }
|
||||
{ source_labels = ["__param_target"]; target_label = "instance"; }
|
||||
{ replacement = "127.0.0.1:${toString config.services.prometheus.exporters.blackbox.port}"; target_label = "__address__"; }
|
||||
];
|
||||
static_configs = [{
|
||||
targets = [
|
||||
"alew.hu-berlin.de"
|
||||
];
|
||||
}];
|
||||
}
|
||||
{
|
||||
job_name = "zaatar";
|
||||
static_configs = [ { targets = [ "zaatar.r:${toString config.services.prometheus.exporters.node.port}" ]; } ];
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
services.prometheus.exporters.blackbox = {
|
||||
enable = true;
|
||||
configFile = (pkgs.formats.yaml {}).generate "blackbox.yaml" blackboxConfig;
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [
|
||||
lokiConfig.server.http_listen_port
|
||||
];
|
||||
|
||||
services.loki = {
|
||||
enable = true;
|
||||
configFile = (pkgs.formats.yaml {}).generate "loki.yaml" lokiConfig;
|
||||
};
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
let
|
||||
moodle-dl-package = pkgs.moodle-dl.overrideAttrs (old: old // {
|
||||
patches = [ <niveum/packages/moodle-dl/telegram-format.patch> ];
|
||||
});
|
||||
in
|
||||
{
|
||||
containers.moodle-dl-borsfaye = {
|
||||
autoStart = true;
|
||||
config = { lib, pkgs, ...}: {
|
||||
imports = [ <niveum/modules/moodle-dl.nix> ];
|
||||
|
||||
services.moodle-dl = {
|
||||
enable = true;
|
||||
startAt = "hourly";
|
||||
package = moodle-dl-package;
|
||||
notifyOnly = true;
|
||||
settings = {
|
||||
telegram = {
|
||||
token = lib.strings.fileContents <system-secrets/telegram/moodle-dl.token>;
|
||||
chat_id = "311425510";
|
||||
send_error_msg = false;
|
||||
};
|
||||
token = lib.strings.fileContents <system-secrets/moodle-dl/faye.token>;
|
||||
moodle_domain = "moodle.hu-berlin.de";
|
||||
moodle_path = "/";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
let
|
||||
moodle-dl-package = pkgs.moodle-dl.overrideAttrs (old: old // {
|
||||
patches = [ <niveum/packages/moodle-dl/telegram-format.patch> ];
|
||||
});
|
||||
in
|
||||
{
|
||||
imports = [ <niveum/modules/moodle-dl.nix> ];
|
||||
|
||||
services.moodle-dl = {
|
||||
enable = true;
|
||||
startAt = "hourly";
|
||||
package = moodle-dl-package;
|
||||
settings = {
|
||||
telegram = {
|
||||
token = lib.strings.fileContents <system-secrets/telegram/moodle-dl.token>;
|
||||
chat_id = "18980945";
|
||||
send_error_msg = false;
|
||||
};
|
||||
token = lib.strings.fileContents <system-secrets/moodle.token>;
|
||||
moodle_domain = "moodle.hu-berlin.de";
|
||||
moodle_path = "/";
|
||||
download_course_ids = [
|
||||
# WS 2020
|
||||
99881 # Dialektologie
|
||||
100183 # Onomastik
|
||||
100353 # Sanskrit I
|
||||
100692 # Sanskrit Tutorium
|
||||
99832 # Germanisch
|
||||
99823 # Gotisch
|
||||
99813 # Altalbanisch
|
||||
98681 # Geistliche Lyrik von Luther bis Lehnert
|
||||
99667 # Antike Mythologie
|
||||
# 52365 # FSR KlassPhil
|
||||
|
||||
# SS 2021
|
||||
104850 # Metrik
|
||||
103274 # Marc Aurel
|
||||
102909 # Sanskrit II
|
||||
104937 # Altirisch
|
||||
104925 # Gradierung und Komparation
|
||||
105264 # Was andere Sprachen anders machen
|
||||
104991 # Warum klingt Orkisch böse
|
||||
105074 # Litauisch
|
||||
103685 # Griechische Sprache und Übersetzung I
|
||||
105455 # Elegia greca
|
||||
105335 # Homerische Epen
|
||||
|
||||
# WS 2021
|
||||
108122 # Griechisch
|
||||
107986 # Altostslavisch
|
||||
107792 # Elegie in Rom
|
||||
107369 # Tusculanae Disputationes
|
||||
108586 # Griechische Religion
|
||||
107988 # Balkanindogermanisch
|
||||
108312 # Altnordisch
|
||||
107281 # NLP
|
||||
108736 # Grammatiktheorie
|
||||
109438 # Warum klingt Orkisch böse
|
||||
108025 # Poetik der Nordgermanen
|
||||
107280 # Statistik
|
||||
108350 # Attische Redner
|
||||
107461 # Argonautika
|
||||
108283 # Digital Classicist
|
||||
109211 # Altlitauisch
|
||||
109185 # Etymologie
|
||||
];
|
||||
download_submissions = true;
|
||||
download_descriptions = true;
|
||||
download_links_in_descriptions = false;
|
||||
download_databases = false;
|
||||
download_forums = false;
|
||||
download_linked_files = false;
|
||||
download_also_with_cookie = false;
|
||||
};
|
||||
};
|
||||
|
||||
fileSystems."/export/moodle" = {
|
||||
device = config.services.moodle-dl.directory;
|
||||
options = [ "bind" ];
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [ 2049 ];
|
||||
|
||||
services.nginx.virtualHosts."moodle.kmein.r" =
|
||||
let
|
||||
identity = lib.strings.fileContents <secrets/eduroam/identity>;
|
||||
password = lib.strings.fileContents <secrets/eduroam/password>;
|
||||
in {
|
||||
basicAuth."${identity}" = password;
|
||||
locations."/" = {
|
||||
root = config.services.moodle-dl.directory;
|
||||
extraConfig = ''
|
||||
autoindex on;
|
||||
charset UTF-8;
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
services.nfs.server = {
|
||||
enable = true;
|
||||
exports = let machines = with (import <niveum/lib>).retiolumAddresses; [kabsa manakish]; in ''
|
||||
/export ${lib.concatMapStringsSep " " (machine: "${machine.ipv4}(fsid=0)") machines}
|
||||
/export/moodle ${lib.concatMapStringsSep " " (machine: "${machine.ipv4}(insecure,rw)") machines}
|
||||
'';
|
||||
};
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
{ pkgs, lib, ... }:
|
||||
let
|
||||
port = 5703;
|
||||
geogen = (pkgs.fetchFromGitHub {
|
||||
owner = "kmein";
|
||||
repo = "scripts";
|
||||
rev = "8945430f27a8c6fd632dd35382cb094abe3543ff";
|
||||
sha256 = "1djyxkynypxsrmdf6idgjszqpcgqyq607rrsvl58p2bpymmwibzb";
|
||||
}) + "/onomastics";
|
||||
inherit (pkgs.callPackage geogen {}) dependencyEnv;
|
||||
in
|
||||
{
|
||||
systemd.services.names = {
|
||||
wants = [ "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
description = "Better clone of geogen.stoepel.net";
|
||||
serviceConfig = {
|
||||
DynamicUser = true;
|
||||
};
|
||||
script = ''
|
||||
cd $(mktemp -d)
|
||||
ln -s "${geogen}/wsgi.py" wsgi.py
|
||||
${dependencyEnv}/bin/gunicorn wsgi:app -b :${toString port}
|
||||
'';
|
||||
};
|
||||
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
recommendedGzipSettings = true;
|
||||
recommendedOptimisation = true;
|
||||
recommendedProxySettings = true;
|
||||
recommendedTlsSettings = true;
|
||||
};
|
||||
|
||||
services.nginx.virtualHosts."names.kmein.r" = {
|
||||
locations."/".proxyPass = "http://127.0.0.1:${toString port}";
|
||||
};
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
programs.nano.nanorc = ''
|
||||
set autoindent
|
||||
set boldtext
|
||||
set morespace
|
||||
set smarthome
|
||||
set tabsize 4
|
||||
set tabstospaces
|
||||
'';
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
{ pkgs, lib, ... }:
|
||||
let
|
||||
passwordFile = path: toString (pkgs.writeText "password" (lib.strings.fileContents path));
|
||||
inherit (import <niveum/lib>) localAddresses;
|
||||
in
|
||||
{
|
||||
services.nextcloud = {
|
||||
enable = true;
|
||||
package = pkgs.nextcloud22;
|
||||
|
||||
https = true;
|
||||
|
||||
autoUpdateApps = {
|
||||
enable = true;
|
||||
startAt = "05:00:00";
|
||||
};
|
||||
|
||||
hostName = "cloud.xn--kiern-0qa.de";
|
||||
|
||||
config = {
|
||||
overwriteProtocol = "https";
|
||||
|
||||
dbtype = "pgsql";
|
||||
dbuser = "nextcloud";
|
||||
dbhost = "/run/postgresql"; # nextcloud will add /.s.PGSQL.5432 by itself
|
||||
dbname = "nextcloud";
|
||||
dbpassFile = passwordFile <system-secrets/nextcloud/database>;
|
||||
adminpassFile = passwordFile <system-secrets/nextcloud/admin>;
|
||||
adminuser = "admin";
|
||||
# extraTrustedDomains = [ "toum.r" ];
|
||||
};
|
||||
};
|
||||
|
||||
services.postgresql = {
|
||||
enable = true;
|
||||
ensureDatabases = [ "nextcloud" ];
|
||||
ensureUsers = [
|
||||
{
|
||||
name = "nextcloud";
|
||||
ensurePermissions."DATABASE nextcloud" = "ALL PRIVILEGES";
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
|
||||
services.nginx.virtualHosts."cloud.xn--kiern-0qa.de" = {
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
};
|
||||
|
||||
# Ensure that postgres is running before running the setup
|
||||
systemd.services."nextcloud-setup" = {
|
||||
requires = ["postgresql.service"];
|
||||
after = ["postgresql.service"];
|
||||
};
|
||||
}
|
||||
@@ -1,5 +1,12 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
nixpkgs = {
|
||||
config.allowUnfree = true;
|
||||
overlays = [
|
||||
(import <nix-writers/pkgs>)
|
||||
(import <stockholm/krebs/5pkgs>)
|
||||
];
|
||||
};
|
||||
# enable `nix flake`
|
||||
nix = {
|
||||
package = pkgs.nixFlakes;
|
||||
|
||||
@@ -1,212 +0,0 @@
|
||||
{ lib, pkgs, config, ... }:
|
||||
let
|
||||
inherit (import <niveum/lib>) tmpfilesConfig serveHtml;
|
||||
|
||||
radioStore = "/var/lib/radio";
|
||||
htgenPort = 8080;
|
||||
stations = {
|
||||
lyrikline = {
|
||||
streamPort = 8001;
|
||||
mpdPort = 6601;
|
||||
description = ''
|
||||
Weltklang. Welt als ewiges Gedicht, das seine Schallspuren durch Raum und Zeit jagt. Endlose Zufallswiedergabe von <a href="//lyrikline.org">lyrikline</a>. — Listen to the sound of voices and poems permeating linguistic and geographic barriers, 24 hours per day.
|
||||
'';
|
||||
};
|
||||
lyrik = {
|
||||
streamPort = 8002;
|
||||
mpdPort = 6602;
|
||||
description = ''
|
||||
Deutsche Lyrik, die du noch nicht gut genug kennst. Tritt in einen Fluss aus Reim und Maß; keine zwei Mal ist er derselbe.
|
||||
'';
|
||||
};
|
||||
};
|
||||
mpd-add-with-tags = pkgs.writers.writeHaskell "mpd-add-with-tags" {
|
||||
libraries = with pkgs.haskellPackages; [ optparse-generic libmpd ];
|
||||
} ''
|
||||
{-# LANGUAGE DeriveGeneric, OverloadedStrings #-}
|
||||
import Control.Monad (void)
|
||||
import Data.String
|
||||
import Network.MPD
|
||||
import Options.Generic
|
||||
|
||||
data Options = Options { url :: String, artist :: Maybe String, title :: Maybe String }
|
||||
deriving (Generic)
|
||||
|
||||
instance ParseRecord Options
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
options <- getRecord "Add to MPD with tags"
|
||||
void $ withMPD $ do
|
||||
songId <- addId (fromString $ url options) Nothing
|
||||
maybe (pure ()) (addTagId songId Artist . fromString) $ artist options
|
||||
maybe (pure ()) (addTagId songId Title . fromString) $ title options
|
||||
'';
|
||||
|
||||
mpcs = lib.mapAttrs (name: station: pkgs.writers.writeDashBin "mpc-${name}" ''
|
||||
MPD_PORT=${toString station.mpdPort} ${pkgs.mpc_cli}/bin/mpc "$@"
|
||||
'') stations;
|
||||
in
|
||||
{
|
||||
imports = [ <stockholm/krebs/3modules/htgen.nix> ];
|
||||
nixpkgs.overlays = [
|
||||
(self: super: { htgen = super.callPackage <stockholm/krebs/5pkgs/simple/htgen> {}; })
|
||||
];
|
||||
|
||||
systemd.tmpfiles.rules = [
|
||||
(tmpfilesConfig {
|
||||
type = "d";
|
||||
path = radioStore;
|
||||
mode = "0755";
|
||||
user = config.users.extraUsers.radio.name;
|
||||
age = "1d";
|
||||
})
|
||||
];
|
||||
|
||||
users.extraUsers.radio = {
|
||||
isSystemUser = true;
|
||||
group = "radio";
|
||||
};
|
||||
users.groups.radio = {};
|
||||
|
||||
krebs.htgen.radio = {
|
||||
port = htgenPort;
|
||||
user.name = "radio";
|
||||
script = ''. ${pkgs.writers.writeDash "meinskript" ''
|
||||
send200() {
|
||||
printf 'HTTP/1.1 200 OK\r\n'
|
||||
printf 'Content-Type: text/html; charset=UTF-8\r\n'
|
||||
printf 'Connection: close\r\n'
|
||||
printf '\r\n'
|
||||
}
|
||||
|
||||
case "$Method $Request_URI" in
|
||||
"GET /lyrik/status")
|
||||
send200
|
||||
video_id="$(
|
||||
${mpcs.lyrik}/bin/mpc-lyrik status -f %file% \
|
||||
| head -n1 \
|
||||
| grep -o 'id=[^&]*' \
|
||||
| sed 's/^id=//g'
|
||||
)"
|
||||
|
||||
${pkgs.youtube-dl}/bin/youtube-dl -j "https://www.youtube.com/watch?v=$video_id" \
|
||||
| ${pkgs.jq}/bin/jq -r '"% [\(.title)](\(.webpage_url))\n\n\(.description)"' \
|
||||
| sed 's/$/ /g' \
|
||||
| ${pkgs.pandoc}/bin/pandoc -s
|
||||
|
||||
exit
|
||||
;;
|
||||
"GET /lyrikline/status")
|
||||
send200
|
||||
|
||||
hash="$(
|
||||
${mpcs.lyrikline}/bin/mpc-lyrikline status -f '%file%' \
|
||||
| head -n 1 \
|
||||
| md5sum \
|
||||
| cut -d' ' -f 1
|
||||
)"
|
||||
url="$(cat ${radioStore}/$hash)"
|
||||
|
||||
echo "<html><body style='margin:0'><iframe style='width:100%;height:100%;border:0' src="$url"></iframe></body></html>"
|
||||
exit
|
||||
;;
|
||||
esac
|
||||
''}'';
|
||||
};
|
||||
|
||||
containers = lib.mapAttrs (name: station: {
|
||||
autoStart = true;
|
||||
config = {config, pkgs, ...}: {
|
||||
services.mpd = {
|
||||
enable = true;
|
||||
network.port = station.mpdPort;
|
||||
extraConfig = ''
|
||||
log_level "default"
|
||||
|
||||
audio_output {
|
||||
name "${name}"
|
||||
type "httpd"
|
||||
encoder "vorbis"
|
||||
port "${toString station.streamPort}"
|
||||
bitrate "128"
|
||||
format "44100:16:2"
|
||||
always_on "yes"
|
||||
tags "yes"
|
||||
}
|
||||
'';
|
||||
};
|
||||
};
|
||||
}) stations;
|
||||
|
||||
environment.systemPackages = lib.attrValues mpcs;
|
||||
|
||||
systemd.services.lyrikline = {
|
||||
after = [ "container@lyrikline.service" ];
|
||||
wantedBy = [ "container@lyrikline.service" ];
|
||||
startAt = "*:00/5";
|
||||
serviceConfig.User = config.users.extraUsers.radio.name;
|
||||
preStart = "${mpcs.lyrikline}/bin/mpc-lyrikline crop || :";
|
||||
script = ''
|
||||
set -efu
|
||||
|
||||
lyrikline=https://www.lyrikline.org
|
||||
for _ in $(seq 1 10); do
|
||||
random_route="$(${pkgs.curl}/bin/curl -sSL "$lyrikline/index.php/tools/getrandompoem" --data-raw 'lang=de' --compressed | ${pkgs.jq}/bin/jq -r .link)"
|
||||
poem_url="$lyrikline$random_route"
|
||||
|
||||
poem_file="$(
|
||||
${pkgs.curl}/bin/curl -sSL "$poem_url" \
|
||||
| grep -o 'https://.*\.mp3' \
|
||||
| head -n1
|
||||
)"
|
||||
|
||||
hash="$(echo "$poem_file" | md5sum | cut -d' ' -f 1)"
|
||||
echo "$poem_file ($hash) -> $poem_url"
|
||||
echo "$poem_url" > "${radioStore}/$hash"
|
||||
|
||||
${mpcs.lyrikline}/bin/mpc-lyrikline add "$poem_file"
|
||||
done
|
||||
|
||||
${mpcs.lyrikline}/bin/mpc-lyrikline play
|
||||
'';
|
||||
};
|
||||
|
||||
systemd.services.lyrik = {
|
||||
after = [ "container@lyrik.service" ];
|
||||
wantedBy = [ "container@lyrik.service" ];
|
||||
preStart = "${mpcs.lyrik}/bin/mpc-lyrik crop || :";
|
||||
restartIfChanged = true;
|
||||
serviceConfig.User = config.users.extraUsers.radio.name;
|
||||
script =
|
||||
let
|
||||
invidious = "https://invidious.silkky.cloud";
|
||||
videoIds = import <niveum/lib/hot-rotation/lyrik.nix>;
|
||||
streams = lib.concatMapStringsSep "\n" (id: "${invidious}/latest_version?id=${id}&itag=251") videoIds;
|
||||
streamsFile = pkgs.writeText "hotrot" streams;
|
||||
in ''
|
||||
set -efu
|
||||
${mpcs.lyrik}/bin/mpc-lyrik add < ${toString streamsFile}
|
||||
|
||||
${mpcs.lyrik}/bin/mpc-lyrik crossfade 5
|
||||
${mpcs.lyrik}/bin/mpc-lyrik random on
|
||||
${mpcs.lyrik}/bin/mpc-lyrik repeat on
|
||||
${mpcs.lyrik}/bin/mpc-lyrik play
|
||||
'';
|
||||
};
|
||||
|
||||
|
||||
services.nginx.virtualHosts."radio.kmein.de" = {
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
locations = lib.mkMerge (
|
||||
[
|
||||
{ "/".extraConfig = serveHtml (import ./station-list.nix { inherit pkgs lib stations; }) pkgs; }
|
||||
] ++ (lib.mapAttrsToList (name: station: {
|
||||
"= /${name}/status".proxyPass = "http://127.0.0.1:${toString htgenPort}";
|
||||
"= /${name}/listen.ogg".proxyPass = "http://127.0.0.1:${toString station.streamPort}";
|
||||
"= /${name}.ogg".return = "301 http://radio.xn--kiern-0qa.de/${name}/listen.ogg"; # legacy
|
||||
}) stations)
|
||||
);
|
||||
};
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
{ pkgs, lib, stations }:
|
||||
let
|
||||
theStations = lib.mapAttrsToList (name: value: value // {name = name;}) stations;
|
||||
in
|
||||
pkgs.writeText "index.html" ''
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>radio.kierán</title>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="//cdn.rawgit.com/necolas/normalize.css/master/normalize.css"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.9.2/css/bulma.min.css"
|
||||
/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
<body>
|
||||
<main class="section">
|
||||
<div class="subtitle is-3">Welcome to</div>
|
||||
<h1 class="title is-1">radio.kierán</h1>
|
||||
|
||||
<div class="columns is-multiline">
|
||||
${lib.concatMapStringsSep "\n" (station: ''
|
||||
<div class="column">
|
||||
<div class="box">
|
||||
<strong class="is-uppercase">${station.name}</strong>
|
||||
(<a href="/${station.name}/status">status</a>, <a href="/${station.name}/listen.ogg">link</a>)
|
||||
|
||||
<p class="has-text-grey">${station.description}</p>
|
||||
<hr/>
|
||||
<audio style="width:100%" controls src="/${station.name}/listen.ogg"/>
|
||||
</div>
|
||||
</div>'') theStations
|
||||
}
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
''
|
||||
@@ -1,69 +0,0 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
let
|
||||
network = "retiolum";
|
||||
|
||||
stateDirectory = "retiolum-map";
|
||||
|
||||
geo-ip-database = "${lib.head config.services.geoipupdate.settings.EditionIDs}.mmdb";
|
||||
geo-ip-database-path = "${config.services.geoipupdate.settings.DatabaseDirectory}/${geo-ip-database}";
|
||||
|
||||
tinc-graph-source = pkgs.fetchFromGitHub {
|
||||
owner = "kmein";
|
||||
repo = "tinc-graph";
|
||||
rev = "1b9c69ffdbdab82d30a23e44f739feea63d94163";
|
||||
sha256 = "0bk4x9l399f80lmz4asx7s5fcsgrfdb6xyymbq884621x4z3d2vp";
|
||||
};
|
||||
tinc-graph = pkgs.callPackage tinc-graph-source {};
|
||||
in
|
||||
{
|
||||
systemd.services.retiolum-index = {
|
||||
description = "Retiolum indexing service";
|
||||
wants = [ "tinc.${network}.service" ];
|
||||
script = ''
|
||||
${tinc-graph}/bin/tinc-graph --geoip-file ${geo-ip-database-path} --network ${network} \
|
||||
| ${pkgs.coreutils}/bin/tee network.json \
|
||||
| ${tinc-graph}/bin/tinc-statistics > statistics.json
|
||||
|
||||
cp ${tinc-graph}/static/map.html map.html
|
||||
cp ${tinc-graph}/static/map.html index.html
|
||||
cp ${tinc-graph}/static/graph.html graph.html
|
||||
'';
|
||||
startAt = "hourly";
|
||||
path = [ pkgs.coreutils pkgs.jq pkgs.tinc_pre ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
User = "root";
|
||||
StateDirectory = stateDirectory;
|
||||
WorkingDirectory = "/var/lib/${stateDirectory}";
|
||||
};
|
||||
};
|
||||
|
||||
services.geoipupdate = {
|
||||
enable = true;
|
||||
settings = {
|
||||
AccountID = 608777;
|
||||
LicenseKey = toString <system-secrets/maxmind/license.key>;
|
||||
EditionIDs = [ "GeoLite2-City" ];
|
||||
};
|
||||
};
|
||||
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
recommendedGzipSettings = true;
|
||||
recommendedOptimisation = true;
|
||||
recommendedProxySettings = true;
|
||||
recommendedTlsSettings = true;
|
||||
virtualHosts."graph.r".locations."/".root = "/var/lib/${stateDirectory}";
|
||||
};
|
||||
|
||||
systemd.services.geoip-share = {
|
||||
after = [ "geoipupdate.service" ];
|
||||
script = let
|
||||
cyberlocker-tools = pkgs.callPackage <stockholm/krebs/5pkgs/simple/cyberlocker-tools> {};
|
||||
in "${cyberlocker-tools}/bin/cput ${geo-ip-database} < ${geo-ip-database-path}";
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
DynamicUser = true;
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
let
|
||||
tarotPort = 7407;
|
||||
tarotFiles = pkgs.fetchzip {
|
||||
url = "https://c.krebsco.de/tarot.zip";
|
||||
sha256 = "0jl5vdwlj17pqp94yj02xgsb1gyvs9i08m83kac0jdnhfjl2f75a";
|
||||
stripRoot = false;
|
||||
};
|
||||
tarotKey = builtins.fetchurl {
|
||||
url = "http://c.krebsco.de/tarot.pdf";
|
||||
sha256 = "1n2m53kjg2vj9dbr70b9jrsbqwdfrcb48l4wswn21549fi24g6dx";
|
||||
};
|
||||
in
|
||||
{
|
||||
krebs.htgen.tarot = {
|
||||
port = tarotPort;
|
||||
user.name = "radio";
|
||||
script = ''. ${pkgs.writers.writeDash "tarot" ''
|
||||
case "$Method $Request_URI" in
|
||||
"GET /")
|
||||
if item=$(${pkgs.findutils}/bin/find ${toString tarotFiles} -type f | ${pkgs.coreutils}/bin/shuf -n1); then
|
||||
card=$(mktemp --tmpdir tarot.XXX)
|
||||
trap 'rm $card' EXIT
|
||||
reverse=$(${pkgs.coreutils}/bin/shuf -i0-1 -n1)
|
||||
if [ "$reverse" -eq 1 ]; then
|
||||
${pkgs.imagemagick}/bin/convert -rotate 180 "$item" "$card"
|
||||
else
|
||||
${pkgs.coreutils}/bin/cp "$item" "$card"
|
||||
fi
|
||||
printf 'HTTP/1.1 200 OK\r\n'
|
||||
printf 'Content-Type: %s\r\n' "$(${pkgs.file}/bin/file -ib "$card")"
|
||||
printf 'Server: %s\r\n' "$Server"
|
||||
printf 'Connection: close\r\n'
|
||||
printf 'Content-Length: %d\r\n' $(${pkgs.coreutils}/bin/wc -c < "$card")
|
||||
printf '\r\n'
|
||||
cat "$card"
|
||||
exit
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
''}'';
|
||||
};
|
||||
|
||||
services.nginx.virtualHosts."tarot.kmein.de" = {
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
locations = {
|
||||
"/".proxyPass = "http://127.0.0.1:${toString tarotPort}";
|
||||
"/files/" = {
|
||||
root = pkgs.linkFarm "tarot" [
|
||||
{ name = "files/key.pdf"; path = tarotKey; }
|
||||
{ name = "files/cards"; path = tarotFiles; }
|
||||
];
|
||||
extraConfig = ''
|
||||
autoindex on;
|
||||
charset UTF-8;
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
114
configs/tuna.nix
114
configs/tuna.nix
@@ -1,114 +0,0 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
let
|
||||
firewall = (import <niveum/lib>).firewall lib;
|
||||
|
||||
streams = import <niveum/lib/streams.nix> {
|
||||
di-fm-key = lib.strings.fileContents <secrets/di.fm/key>;
|
||||
};
|
||||
multi-room-audio-port = 8000;
|
||||
password = lib.strings.fileContents <system-secrets/mpd-web.key>;
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
<niveum/modules/tuna.nix>
|
||||
];
|
||||
|
||||
services.syncthing = let mpd-directory = config.services.mpd.dataDir; in {
|
||||
enable = true;
|
||||
user = config.services.mpd.user; # config.users.extraUsers.moodle.name;
|
||||
openDefaultPorts = true;
|
||||
configDir = "${mpd-directory}/.config/syncthing";
|
||||
dataDir = "${mpd-directory}/.config/syncthing";
|
||||
cert = toString <system-secrets/syncthing/cert.pem>;
|
||||
key = toString <system-secrets/syncthing/key.pem>;
|
||||
devices = {
|
||||
inherit ((import <niveum/lib>).syncthing.devices) kabsa manakish heym;
|
||||
};
|
||||
folders.${config.services.mpd.musicDirectory} = {
|
||||
devices = [ "heym" "kabsa" "manakish" ];
|
||||
id = "music";
|
||||
type = "receiveonly";
|
||||
};
|
||||
};
|
||||
|
||||
services.mpd = {
|
||||
enable = true;
|
||||
network.listenAddress = "0.0.0.0";
|
||||
extraConfig = ''
|
||||
log_level "default"
|
||||
auto_update "yes"
|
||||
|
||||
audio_output {
|
||||
type "pulse"
|
||||
name "zaatar single room audio system"
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
environment.systemPackages = [ pkgs.mpc_cli ];
|
||||
|
||||
networking.firewall =
|
||||
let
|
||||
dport = config.services.mpd.network.port;
|
||||
protocol = "tcp";
|
||||
rules = [
|
||||
(firewall.accept { inherit dport protocol; source = "192.168.0.0/16"; })
|
||||
(firewall.accept { inherit dport protocol; source = "127.0.0.0/8"; })
|
||||
];
|
||||
in {
|
||||
allowedTCPPorts = [ 80 ];
|
||||
extraCommands = firewall.addRules rules;
|
||||
extraStopCommands = firewall.removeRules rules;
|
||||
};
|
||||
|
||||
system.activationScripts.mpd-playlists =
|
||||
let playlistFile = pkgs.writeText "radio.m3u" (lib.concatMapStringsSep "\n" (lib.getAttr "stream") streams);
|
||||
in ''
|
||||
rm -rf /var/lib/mpd/playlists
|
||||
install -d /var/lib/mpd/playlists
|
||||
ln -sfn "${toString playlistFile}" "/var/lib/mpd/playlists/radio.m3u"
|
||||
'';
|
||||
|
||||
services.tuna = {
|
||||
enable = true;
|
||||
# stationsFile = "/etc/tuna/stations.json";
|
||||
stations = lib.lists.imap0 (id: {desc ? "", logo ? "https://picsum.photos/seed/${builtins.hashString "md5" stream}/300", stream, station}: { inherit id desc logo stream station; }) streams;
|
||||
webPort = 8080;
|
||||
};
|
||||
|
||||
systemd.services.tuna-stations =
|
||||
let
|
||||
stations = lib.lists.imap0 (id: {desc ? "", logo ? "https://picsum.photos/seed/${builtins.hashString "md5" stream}/300", stream, station}: { inherit id desc logo stream station; }) streams;
|
||||
stationsJson = (pkgs.formats.json {}).generate "stations.json" stations;
|
||||
in {
|
||||
wantedBy = [ "tuna.service" ];
|
||||
startAt = "hourly";
|
||||
script = ''
|
||||
mkdir -p /etc/tuna
|
||||
antenne_asb_url=$(
|
||||
${pkgs.curl}/bin/curl -sS 'https://www.caster.fm/widgets/em_player.php?jsinit=true&uid=529295&t=blue&c=' \
|
||||
| grep streamUrl \
|
||||
| sed ${lib.escapeShellArg "s/^.*'\\([^']*\\)'.*/\\1/"}
|
||||
)
|
||||
${pkgs.jq}/bin/jq "map(if .station == \"Antenne ASB\" then .stream |= \"$antenne_asb_url\" else . end)" < ${stationsJson} > /etc/tuna/stations.json
|
||||
'';
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
recommendedGzipSettings = true;
|
||||
recommendedOptimisation = true;
|
||||
recommendedProxySettings = true;
|
||||
recommendedTlsSettings = true;
|
||||
virtualHosts."radio.kmein.r" = {
|
||||
basicAuth.dj = password;
|
||||
locations."/" = {
|
||||
proxyPass = "http://127.0.0.1:${toString config.services.tuna.webPort}";
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
*/
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
{ pkgs, config, lib, ... }:
|
||||
let
|
||||
inherit (import <niveum/lib>) kieran;
|
||||
|
||||
urlwatchDir = "/var/lib/urlwatch";
|
||||
|
||||
urlsFile = pkgs.writeText "urls" (builtins.concatStringsSep "\n---\n" (map builtins.toJSON urls));
|
||||
|
||||
urls = [
|
||||
{
|
||||
name = "Corona-Verordnung";
|
||||
url = "https://www.berlin.de/corona/massnahmen/verordnung/";
|
||||
filter = [ { css = "[role=main]"; } "html2text" "strip" ];
|
||||
}
|
||||
{
|
||||
name = "HU Semester";
|
||||
url = "https://agnes.hu-berlin.de/lupo/rds?state=change&type=6&moduleParameter=semesterSelect&nextdir=change&next=SearchSelect.vm&subdir=applications&targettype=7&targetstate=change&getglobal=semester";
|
||||
filter = [ { css = "fieldset"; } "html2text" "strip" ];
|
||||
}
|
||||
{
|
||||
name = "Lammla 2021";
|
||||
url = "http://lammla.info/index.php?reihe=30";
|
||||
filter = [ "html2text" "strip" ];
|
||||
}
|
||||
{
|
||||
name = "Tatort";
|
||||
url = "https://www.daserste.de/unterhaltung/krimi/tatort/vorschau/index.html";
|
||||
filter = [
|
||||
"html2text"
|
||||
"strip"
|
||||
{
|
||||
shellpipe = ''
|
||||
${pkgs.gnused}/bin/sed 's/ / /g;s/))/&\n/g;s/ \+/ /g'
|
||||
'';
|
||||
}
|
||||
];
|
||||
}
|
||||
{
|
||||
name = "Kratylos";
|
||||
url = "https://kratylos.reichert-online.org/current_issue/KRATYLOS";
|
||||
filter = [ { element-by-id = "content"; } "html2text" "strip" ];
|
||||
}
|
||||
{
|
||||
name = "Zeno Free E-Books";
|
||||
url = "http://www.zeno.org/Lesesaal/M/E-Books";
|
||||
filter = [ { element-by-class = "zenoCOMain"; } "html2text" "strip" ];
|
||||
}
|
||||
{
|
||||
name = "Indogermanische Forschungen";
|
||||
url = "https://www.degruyter.com/journal/key/INDO/html";
|
||||
filter = [ { element-by-id = "latestIssue"; } "html2text" "strip" ];
|
||||
}
|
||||
{
|
||||
name = "IG Neuigkeiten";
|
||||
url = "https://www.indogermanistik.org/aktuelles/neuigkeiten.html";
|
||||
filter = [ { css = "[itemprop=articleBody]"; } "html2text" "strip" ];
|
||||
}
|
||||
{
|
||||
name = "IG Tagungen";
|
||||
url = "https://www.indogermanistik.org/tagungen/tagungen-der-ig.html";
|
||||
filter = [ { css = "[itemprop=articleBody]"; } "html2text" "strip" ];
|
||||
}
|
||||
{
|
||||
name = "Christian-Metz-Blamage";
|
||||
url = "https://www.deutschlandfunk.de/meine-nacht-schlaeft-nicht-pflanze-mich-nicht-in-dein-herz.700.de.html?dram:article_id=486475";
|
||||
filter = [ { element-by-class = "dlf-articledetail"; } "html2text" "strip" ];
|
||||
}
|
||||
{
|
||||
name = "fxght.or.flxght";
|
||||
url = "https://api.tellonym.me/profiles/name/fxght.or.flxght?limit=20";
|
||||
headers.tellonym-client = "web:0.52.0";
|
||||
filter = [
|
||||
{
|
||||
shellpipe = ''
|
||||
${pkgs.jq}/bin/jq '.answers | map({
|
||||
question: .tell,
|
||||
answer: .answer,
|
||||
date: .createdAt,
|
||||
media: .media | map(.url)
|
||||
})'
|
||||
'';
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
|
||||
configFile = (pkgs.formats.yaml {}).generate "urlwatch.yaml" {
|
||||
display = {
|
||||
error = true;
|
||||
new = true;
|
||||
unchanged = false;
|
||||
};
|
||||
report = {
|
||||
email = {
|
||||
enabled = true;
|
||||
from = "2210@cock.li";
|
||||
html = false;
|
||||
method = "smtp";
|
||||
smtp = {
|
||||
host = "mail.cock.li";
|
||||
port = 587;
|
||||
starttls = true;
|
||||
auth = true;
|
||||
insecure_password = lib.strings.fileContents <secrets/mail/cock>;
|
||||
};
|
||||
subject = "{count} changes: {jobs}";
|
||||
to = kieran.email;
|
||||
};
|
||||
telegram = {
|
||||
enabled = true;
|
||||
bot_token = lib.strings.fileContents <system-secrets/telegram/kmein.token>;
|
||||
chat_id = "-1001504043752";
|
||||
};
|
||||
html.diff = "unified";
|
||||
stdout = {
|
||||
color = true;
|
||||
enabled = true;
|
||||
};
|
||||
text.footer = false;
|
||||
# telegram = {
|
||||
# enabled = false;
|
||||
# bot_token = lib.strings.fileContents <system-secrets/telegram/kmein.token>;
|
||||
# chat_id = [ "18980945" ];
|
||||
# };
|
||||
};
|
||||
};
|
||||
urlwatch = pkgs.urlwatch.overrideAttrs (attrs: {
|
||||
patches = [ <niveum/packages/urlwatch-insecure.patch> ];
|
||||
});
|
||||
in
|
||||
{
|
||||
users.extraUsers.urlwatch = {
|
||||
home = urlwatchDir;
|
||||
createHome = true;
|
||||
isSystemUser = true;
|
||||
group = "urlwatch";
|
||||
};
|
||||
|
||||
users.groups.urlwatch = {};
|
||||
|
||||
systemd.services.urlwatch = {
|
||||
enable = true;
|
||||
startAt = "*-*-* 05:00:00";
|
||||
script = ''
|
||||
${urlwatch}/bin/urlwatch \
|
||||
--config=${lib.escapeShellArg configFile} \
|
||||
--urls=${lib.escapeShellArg urlsFile}
|
||||
'';
|
||||
serviceConfig = {
|
||||
User = config.users.extraUsers.urlwatch.name;
|
||||
Group = config.users.groups.urlwatch.name;
|
||||
WorkingDirectory = config.users.extraUsers.urlwatch.home;
|
||||
PermissionsStartOnly = "true";
|
||||
PrivateTmp = "true";
|
||||
SyslogIdentifier = "urlwatch";
|
||||
Type = "oneshot";
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
{ lib, pkgs, ... }:
|
||||
let
|
||||
inherit (import <niveum/lib>) kieran;
|
||||
relayPassword = lib.fileContents <system-secrets/weechat/relay>;
|
||||
in {
|
||||
systemd.services.weechat =
|
||||
let
|
||||
tmux = pkgs.writers.writeDash "tmux" ''
|
||||
exec ${pkgs.tmux}/bin/tmux -f ${pkgs.writeText "tmux.conf" ''
|
||||
set-option -g prefix `
|
||||
unbind-key C-b
|
||||
bind ` send-prefix
|
||||
|
||||
set-option -g status off
|
||||
set-option -g default-terminal screen-256color
|
||||
|
||||
#use session instead of windows
|
||||
bind-key c new-session
|
||||
bind-key p switch-client -p
|
||||
bind-key n switch-client -n
|
||||
bind-key C-s switch-client -l
|
||||
''} "$@"
|
||||
'';
|
||||
weechat = pkgs.weechat.override {
|
||||
configure = { ... }: {
|
||||
scripts = [ pkgs.weechatScripts.weechat-autosort pkgs.weechatScripts.colorize_nicks pkgs.weechatScripts.weechat-matrix ];
|
||||
init = let
|
||||
coolColors = lib.lists.subtractLists (lib.range 52 69 ++ lib.range 231 248) (lib.range 31 254);
|
||||
nick = "kmein";
|
||||
in ''
|
||||
/mouse enable
|
||||
/set irc.server_default.nicks "${nick}"
|
||||
/set irc.server_default.msg_part "tschö mit ö"
|
||||
/set irc.server_default.msg_quit "ciao kakao"
|
||||
/set irc.server_default.msg_kick "warum machst du diese?"
|
||||
/set irc.server_default.realname "${kieran.name}"
|
||||
|
||||
/set irc.look.color_nicks_in_nicklist "on"
|
||||
/set weechat.color.chat_nick_colors "${lib.concatMapStringsSep "," toString coolColors}"
|
||||
|
||||
/server add hackint irc.hackint.org/6697 -ipv6 -ssl
|
||||
/server add libera irc.libera.chat/6697 -ssl
|
||||
/server add oftc irc.oftc.net/6697 -ssl -ipv6
|
||||
/server add retiolum irc.r
|
||||
/server add news news.r
|
||||
/matrix server add nibbana nibbana.jp
|
||||
|
||||
/alias add mod /quote omode $channel +o $nick
|
||||
|
||||
/relay add weechat 9000
|
||||
/set relay.network.password ${relayPassword}
|
||||
|
||||
/set matrix.server.nibbana.username ${nick}
|
||||
/set matrix.server.nibbana.password "${lib.strings.fileContents <system-secrets/matrix/nibbana>}"
|
||||
|
||||
/set irc.server.oftc.command /msg nickserv IDENTIFY ${lib.strings.fileContents <system-secrets/irc/oftc>};/msg nickserv SET CLOAK ON
|
||||
/set irc.server.oftc.autojoin "#osm,#osm-de,#home-manager"
|
||||
|
||||
/set irc.server.hackint.autojoin "#krebs,#nixos,#the_playlist"
|
||||
/set irc.server.hackint.sasl_mechanism plain
|
||||
/set irc.server.hackint.sasl_username ${nick}
|
||||
/set irc.server.hackint.sasl_password ${lib.strings.fileContents <system-secrets/irc/hackint>}
|
||||
|
||||
/set irc.server.libera.autojoin "#flipdot,#haskell,#nixos,#fysi,#binaergewitter"
|
||||
/set irc.server.libera.sasl_mechanism plain
|
||||
/set irc.server.libera.sasl_username ${nick}
|
||||
/set irc.server.libera.sasl_password ${lib.strings.fileContents <system-secrets/irc/libera>}
|
||||
|
||||
/set irc.server.retiolum.autojoin "#xxx,#brockman,#flix,#autowifi"
|
||||
/set irc.server.retiolum.command "/oper admin aidsballs;/msg nickserv always-on true;/msg nickserv autoreplay-missed on;/msg nickserv auto-away"
|
||||
/set irc.server.retiolum.sasl_mechanism plain
|
||||
/set irc.server.retiolum.sasl_username ${nick}
|
||||
/set irc.server.retiolum.sasl_password ${lib.strings.fileContents <system-secrets/irc/retiolum>}
|
||||
|
||||
/set irc.server.news.autojoin "#cook,#drachengame,#oepnv,#kmeinung,#memes"
|
||||
/set irc.server.news.command "/oper aids balls"
|
||||
/set logger.level.irc.news 0
|
||||
|
||||
/filter addreplace zerocovid * * [kc]orona|💉|🤒|😷|[kc]ovid|virus|lockdown|va[kc][sc]in|mutante|mutation|impf|pandemi|κορ[ωο]ν[αο]ϊό|корона|expert|infe[ck]t|infizi|in[cz]iden[cz]|sars-cov|drosten|virolog|lauterbach|delta|omi[ck]ron|epidemi|booster|r-wert
|
||||
/filter addreplace joinquit * irc_join,irc_part,irc_quit,irc_nick *
|
||||
/filter addreplace playlist_topic irc.*.#the_playlist irc_topic *
|
||||
/filter addreplace brockman_notice irc.news.* irc_notice *
|
||||
|
||||
/set irc.look.server_buffer independent
|
||||
|
||||
/connect libera
|
||||
/connect oftc
|
||||
/connect hackint
|
||||
/connect retiolum
|
||||
/connect news
|
||||
/matrix connect nibbana
|
||||
'';
|
||||
};
|
||||
};
|
||||
in {
|
||||
description = "Weechat bouncer";
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
restartIfChanged = true;
|
||||
path = [ pkgs.alacritty.terminfo ];
|
||||
environment.WEECHAT_HOME = "/var/lib/weechat";
|
||||
script = "${tmux} -2 new-session -d -s IM ${weechat}/bin/weechat";
|
||||
preStop = "${tmux} kill-session -t IM";
|
||||
serviceConfig = {
|
||||
User = "weechat";
|
||||
RemainAfterExit = true;
|
||||
Type = "oneshot";
|
||||
};
|
||||
};
|
||||
|
||||
users.groups.weechat = {};
|
||||
users.extraUsers.weechat = {
|
||||
useDefaultShell = true;
|
||||
openssh.authorizedKeys.keys = kieran.sshKeys pkgs ++ [
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC+KVDmYYH7mA8v81e9O3swXm3ZVYY9t4HP65ud61uXy weechat_android@heym"
|
||||
];
|
||||
createHome = true;
|
||||
group = "weechat";
|
||||
home = "/var/lib/weechat";
|
||||
isSystemUser = true;
|
||||
packages = [ pkgs.tmux ];
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user