me like nix
0

Configure Feed

Select the types of activity you want to include in your feed.

1{ 2 pkgs, 3 lib, 4 config, 5 inputs, 6 ... 7}: 8 9let 10 jellyfinKodiSyncQueue = pkgs.fetchzip { 11 url = "https://repo.jellyfin.org/releases/plugin/kodi-sync-queue/kodi-sync-queue_15.0.0.0.zip"; 12 stripRoot = false; 13 hash = "sha256-xtlG3UQ/WClt/Hvxe+oId2CeJ+PWMDXBUJXh5+k+mZQ="; 14 }; 15 16 bambu-studio = 17 let 18 pname = "bambu-studio"; 19 version = "02.05.00.67"; 20 ubuntu_version = "24.04_PR-9540"; 21 22 src = pkgs.fetchurl { 23 url = "https://github.com/bambulab/BambuStudio/releases/download/v${version}/Bambu_Studio_ubuntu-${ubuntu_version}.AppImage"; 24 hash = "sha256-3ubZblrsOJzz1p34QiiwiagKaB7nI8xDeadFWHBkWfg="; 25 }; 26 27 appimage-contents = pkgs.appimageTools.extractType2 { 28 inherit src pname version; 29 }; 30 31 wrapped = pkgs.appimageTools.wrapType2 { 32 inherit src pname version; 33 34 profile = '' 35 export SSL_CERT_FILE="${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt" 36 export GIO_MODULE_DIR="${pkgs.glib-networking}/lib/gio/modules/" 37 export __GLX_VENDOR_LIBRARY_NAME=nvidia 38 ''; 39 40 extraPkgs = 41 p: with p; [ 42 cacert 43 glib 44 glib-networking 45 gst_all_1.gst-plugins-bad 46 gst_all_1.gst-plugins-base 47 gst_all_1.gst-plugins-good 48 webkitgtk_4_1 49 ]; 50 }; 51 in 52 pkgs.runCommand "bambu-studio-${version}" { } '' 53 mkdir -p $out/bin 54 ln -s ${wrapped}/bin/${pname} $out/bin/bambu-studio 55 ln -s ${wrapped}/bin/${pname} $out/bin/BambuStudio 56 57 # Install desktop file with correct exec path 58 mkdir -p $out/share/applications 59 substitute ${appimage-contents}/BambuStudio.desktop $out/share/applications/BambuStudio.desktop \ 60 --replace-fail "Exec=AppRun" "Exec=$out/bin/BambuStudio" 61 62 # Install icons 63 if [ -d ${appimage-contents}/usr/share/icons ]; then 64 cp -r ${appimage-contents}/usr/share/icons $out/share/ 65 fi 66 ''; 67 # Steam/gamescope calls steamos-session-select when the user presses 68 # "Switch to Desktop". Without this script, the button does nothing. 69 # Returning 0 lets gamescope proceed to exit, returning to greetd/regreet. 70 steamos-session-select = pkgs.writeShellScriptBin "steamos-session-select" '' 71 echo "Switching session to: $1" 72 ''; 73 74 # Pin gamescope to 3.14.29 — versions 3.15+ crash on NVIDIA due to 75 # a confirmed driver bug (#5701801) in Vulkan YCbCr sampler pipeline compilation. 76 gamescope_3_14 = pkgs.gamescope.overrideAttrs (old: { 77 version = "3.14.29"; 78 src = pkgs.fetchFromGitHub { 79 owner = "ValveSoftware"; 80 repo = "gamescope"; 81 tag = "3.14.29"; 82 fetchSubmodules = true; 83 hash = "sha256-q3HEbFqUeNczKYUlou+quxawCTjpM5JNLrML84tZVYE="; 84 }; 85 # Drop the system-libraries fetchpatch (3rd patch) — only applies to 3.16.x 86 patches = lib.take 2 (old.patches or []); 87 # 3.14.29 uses pkg-config for glm/stb, not meson subprojects 88 mesonFlags = builtins.filter 89 (f: builtins.match ".*glm_include_dir.*" f == null 90 && builtins.match ".*stb_include_dir.*" f == null) 91 (old.mesonFlags or []); 92 # Fix vendored OpenVR CMakeLists.txt requiring CMake < 3.5 (incompatible with CMake 4.x) 93 env = (old.env or { }) // { CMAKE_POLICY_VERSION_MINIMUM = "3.5"; }; 94 # default_extras_install.sh doesn't exist in 3.14.29; 95 # also provide glm/stb as meson subprojects pointing to system packages 96 postPatch = builtins.replaceStrings 97 [ "patchShebangs default_extras_install.sh" ] [ "" ] 98 (old.postPatch or "") 99 + '' 100 rm -rf subprojects/glm subprojects/glm.wrap subprojects/stb subprojects/stb.wrap 101 mkdir -p subprojects/glm subprojects/stb 102 103 cat > subprojects/glm/meson.build << 'GLMEOF' 104 project('glm', 'cpp', version: '1.0.0') 105 glm_dep = declare_dependency(include_directories: include_directories('${lib.getInclude pkgs.glm}/include', is_system: true)) 106 meson.override_dependency('glm', glm_dep) 107 GLMEOF 108 109 cat > subprojects/stb/meson.build << 'STBEOF' 110 project('stb', 'c', version: '0.0.1') 111 stb_dep = declare_dependency(include_directories: include_directories('${lib.getInclude pkgs.stb}/include/stb', is_system: true)) 112 meson.override_dependency('stb', stb_dep) 113 STBEOF 114 ''; 115 }); 116in 117{ 118 imports = [ 119 # Include the results of the hardware scan. 120 ./hardware-configuration.nix 121 ../common/common.nix 122 ]; 123 124 networking.hostName = "mira"; # Define your hostname. 125 126 # Prevent NetworkManager from managing USB Ethernet 127 networking.networkmanager.unmanaged = [ "interface-name:enp0s20f0u4u3" ]; 128 129 # ZRAM swap to prevent OOM freezes 130 zramSwap = { 131 enable = true; 132 memoryPercent = 50; 133 }; 134 135 # Kill runaway processes before the system locks up 136 services.earlyoom = { 137 enable = true; 138 freeMemThreshold = 5; 139 freeSwapThreshold = 5; 140 enableNotifications = true; 141 }; 142 # networking.wireless.enable = true; # Enables wireless support via wpa_supplicant. 143 144 # Configure network proxy if necessary 145 # networking.proxy.default = "http://user:password@proxy:port/"; 146 # networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain"; 147 148 # this is like a network devices discovery thing 149 services.avahi = { 150 enable = true; 151 nssmdns4 = true; 152 openFirewall = true; 153 }; 154 155 services.copyparty.enable = true; 156 157 services.openssh = { 158 enable = true; 159 settings = { 160 PasswordAuthentication = false; 161 KbdInteractiveAuthentication = false; 162 PermitRootLogin = "no"; 163 AllowUsers = [ "sean" ]; 164 }; 165 }; 166 167 users.users.sean.openssh.authorizedKeys.keys = [ 168 "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDCIqgZ7kedxo+mOW7YG73Vp3zel3h180y3GKvHtRsXfGlpIIvRDy7pgCBQ4AGXYD4y78URQmFohYSAPqCPOPaWcU2un3XG9KvCzEsHmsbskPonitUmCiKvrKkb6oW4jCBtd7AEtBn+AiajAQFtPZ7NN2Df3AmTypvR6Irg7R+nxnfc9NTIHmGvxSDyWcbb4pguL20sctUSqGL6xGh8q/bqhdOThSimM+z9bEUNxK/5rPhwkNniMrp4pJcUrUiAh5/4DiRFG6KT+oeg+/myoz/Z1sPvAs7u/8JDQI4RshRD8Hu0oTkRBN6Hxj478q2SXbeBUZlD6IdjP3RhGpmSecoDdtWqKbpuV3eVRtQtba3KL86GBeV/bugaOdJ1Aud+1SOFJreAAuvxzMMKT+cdQZk6oOPP148DA/No+mDm/2S43lcdCXh79wA6YRAmKQ8jmZxTCtPutrvuZK1rguvvUlEoG/vhdNHh7eDa4Td07V6bjCRPUl8qk/e4M0E3pwsTlZc=" 169 "no-touch-required sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAILdilHXHdAP/V8Zq28EzHKtLAMMaFPu4+1det2N50QfhAAAABHNzaDo= sean@framework16" 170 ]; 171 172 # List services that you want to enable: 173 services.flaresolverr.enable = true; 174 age.secrets.wireguard.file = ../../secrets/wireguard.age; 175 176 nixarr = { 177 enable = true; 178 mediaDir = "/mnt/storage1/nixarr/media"; 179 vpn = { 180 enable = true; 181 wgConf = config.age.secrets.wireguard.path; 182 }; 183 184 jellyfin = { 185 enable = true; 186 openFirewall = true; 187 }; 188 189 transmission = { 190 enable = true; 191 vpn.enable = true; 192 }; 193 sabnzbd = { 194 enable = true; 195 vpn.enable = true; 196 openFirewall = true; 197 }; 198 199 prowlarr.enable = true; 200 radarr.enable = true; 201 sonarr.enable = true; 202 jellyseerr = { 203 enable = true; 204 openFirewall = true; 205 }; 206 207 recyclarr = { 208 enable = true; 209 configuration = { 210 sonarr = { 211 series = { 212 base_url = "http://localhost:8989"; 213 api_key = "!env_var SONARR_API_KEY"; 214 quality_definition = { 215 type = "series"; 216 }; 217 delete_old_custom_formats = true; 218 custom_formats = [ 219 { 220 trash_ids = [ 221 "85c61753df5da1fb2aab6f2a47426b09" # BR-DISK 222 "9c11cd3f07101cdba90a2d81cf0e56b4" # LQ 223 ]; 224 assign_scores_to = [ 225 { 226 name = "WEB-DL (1080p)"; 227 score = -10000; 228 } 229 ]; 230 } 231 ]; 232 }; 233 }; 234 radarr = { 235 movies = { 236 base_url = "http://localhost:7878"; 237 api_key = "!env_var RADARR_API_KEY"; 238 quality_definition = { 239 type = "movie"; 240 }; 241 delete_old_custom_formats = true; 242 custom_formats = [ 243 { 244 trash_ids = [ 245 "570bc9ebecd92723d2d21500f4be314c" # Remaster 246 "eca37840c13c6ef2dd0262b141a5482f" # 4K Remaster 247 ]; 248 assign_scores_to = [ 249 { 250 name = "HD Bluray + WEB"; 251 score = 25; 252 } 253 ]; 254 } 255 ]; 256 }; 257 }; 258 }; 259 }; 260 }; 261 262 # Install Kodi Sync Queue plugin into Jellyfin 263 systemd.services.jellyfin.serviceConfig.ExecStartPre = 264 let 265 pluginDir = "/data/.state/nixarr/jellyfin/data/plugins/Kodi Sync Queue/15.0.0.0"; 266 in 267 pkgs.writeShellScript "install-jellyfin-plugins" '' 268 mkdir -p "${pluginDir}" 269 cp -f ${jellyfinKodiSyncQueue}/*.dll ${jellyfinKodiSyncQueue}/meta.json "${pluginDir}/" 270 ''; 271 272 # MQTT broker for Home Assistant (Tasmota devices, Frigate) 273 services.mosquitto = { 274 enable = true; 275 listeners = [ 276 { 277 acl = [ "pattern readwrite #" ]; 278 omitPasswordAuth = true; 279 settings.allow_anonymous = true; 280 } 281 ]; 282 }; 283 284 # Frigate NVR for camera recording and AI object detection 285 services.frigate = { 286 enable = true; 287 hostname = "frigate"; 288 settings = { 289 mqtt = { 290 enabled = true; 291 host = "localhost"; 292 port = 1883; 293 }; 294 295 detectors = { 296 cpu = { 297 type = "cpu"; 298 num_threads = 2; 299 }; 300 }; 301 302 cameras = { 303 picam = { 304 enabled = true; 305 ffmpeg = { 306 hwaccel_args = "preset-nvidia-h264"; 307 inputs = [ 308 { 309 path = "rtsp://pi:8554/picam"; 310 roles = [ 311 "detect" 312 "record" 313 ]; 314 } 315 ]; 316 }; 317 detect = { 318 enabled = true; 319 width = 1920; 320 height = 1080; 321 fps = 3; 322 }; 323 record = { 324 enabled = true; 325 retain = { 326 days = 7; 327 mode = "active_objects"; 328 }; 329 }; 330 snapshots = { 331 enabled = true; 332 bounding_box = true; 333 retain = { 334 default = 14; 335 }; 336 }; 337 objects = { 338 track = [ 339 "person" 340 "dog" 341 "cat" 342 "car" 343 ]; 344 }; 345 zones = { 346 driveway = { 347 coordinates = "0,0.243,1,0.544,1,1,0,1,0,0.75"; 348 objects = [ 349 "person" 350 "car" 351 "dog" 352 "cat" 353 ]; 354 }; 355 }; 356 }; 357 358 pizerocam = { 359 enabled = true; 360 ffmpeg = { 361 hwaccel_args = "preset-nvidia-h264"; 362 inputs = [ 363 { 364 path = "rtsp://pizero:8554/pizerocam"; 365 roles = [ "record" ]; 366 } 367 ]; 368 }; 369 detect = { 370 enabled = false; 371 }; 372 record = { 373 enabled = true; 374 retain = { 375 days = 2; 376 mode = "all"; 377 }; 378 }; 379 }; 380 }; 381 382 record = { 383 enabled = true; 384 retain = { 385 days = 7; 386 mode = "active_objects"; 387 }; 388 }; 389 }; 390 }; 391 392 # Frigate manages many ffmpeg child processes that ignore SIGTERM; 393 # shorten the stop timeout so it doesn't block shutdown for 90s. 394 systemd.services.frigate.serviceConfig = { 395 TimeoutStopSec = 5; 396 KillMode = "mixed"; # SIGTERM to main, SIGKILL to children after timeout 397 }; 398 399 # Home Assistant service 400 services.home-assistant = { 401 enable = true; 402 customComponents = with pkgs.home-assistant-custom-components; [ 403 frigate 404 ]; 405 extraComponents = [ 406 "esphome" 407 "met" 408 "radio_browser" 409 "homekit" 410 "homekit_controller" 411 "isal" 412 "mqtt" 413 "tasmota" 414 "wiz" 415 "google_translate" # TTS - was missing gtts module 416 "ecobee" # Was missing pyecobee module 417 "ibeacon" # Was missing ibeacon_ble module 418 "go2rtc" # Camera streaming 419 "generic" # Generic camera integration 420 ]; 421 config = { 422 homeassistant = { 423 time_zone = "America/Toronto"; 424 }; 425 default_config = { }; 426 zeroconf = { }; 427 # MQTT configuration - broker must be set up via UI 428 mqtt = { }; 429 # Automations 430 automation = [ 431 { 432 id = "1761448856909"; 433 alias = "Lower heat at night"; 434 trigger = [ 435 { 436 platform = "time"; 437 at = "23:00:00"; 438 } 439 ]; 440 condition = [ ]; 441 action = [ 442 { 443 action = "climate.set_temperature"; 444 target.device_id = "bfe22d32a4532f8ae991d6daffb48267"; 445 data = { 446 hvac_mode = "heat"; 447 temperature = 18; 448 }; 449 } 450 ]; 451 mode = "single"; 452 } 453 { 454 id = "1766200000001"; 455 alias = "Raise heat in morning"; 456 trigger = [ 457 { 458 platform = "time"; 459 at = "06:00:00"; 460 } 461 ]; 462 condition = [ ]; 463 action = [ 464 { 465 action = "climate.set_temperature"; 466 target.device_id = "bfe22d32a4532f8ae991d6daffb48267"; 467 data = { 468 hvac_mode = "heat"; 469 temperature = 21; 470 }; 471 } 472 ]; 473 mode = "single"; 474 } 475 { 476 id = "1766153071796"; 477 alias = "Close Garage Door"; 478 trigger = [ 479 { 480 platform = "device"; 481 device_id = "d8dedd8cd0ce1488d9830c455bb0a761"; 482 domain = "cover"; 483 entity_id = "cf36763543169888aa106b1acb02ad72"; 484 type = "opened"; 485 for = { 486 hours = 0; 487 minutes = 10; 488 seconds = 0; 489 }; 490 } 491 ]; 492 condition = [ ]; 493 action = [ 494 { 495 device_id = "d8dedd8cd0ce1488d9830c455bb0a761"; 496 domain = "cover"; 497 entity_id = "cf36763543169888aa106b1acb02ad72"; 498 type = "close"; 499 } 500 ]; 501 mode = "single"; 502 } 503 ]; 504 }; 505 }; 506 507 508 # NVIDIA needs GBM/EGL env vars for cage (wlroots) to initialize GPU on greetd restart 509 services.greetd.settings.default_session.command = lib.mkOverride 49 510 "${pkgs.dbus}/bin/dbus-run-session ${lib.getExe pkgs.cage} -s -d -- env GBM_BACKEND=nvidia-drm __GLX_VENDOR_LIBRARY_NAME=nvidia GDK_SCALE=2 ${lib.getExe pkgs.greetd.regreet}"; 511 512 programs.steam = { 513 enable = true; 514 remotePlay.openFirewall = true; 515 gamescopeSession = { 516 enable = true; 517 args = [ 518 "-r" "120" 519 "-R" "120" 520 ]; 521 env = { 522 STEAM_DESKTOP_SESSION = "niri"; 523 ENABLE_GAMESCOPE_WSI = "0"; 524 }; 525 }; 526 extraCompatPackages = with pkgs; [ 527 proton-ge-bin 528 ]; 529 }; 530 531 programs.gamemode.enable = true; 532 533 programs.gamescope = { 534 enable = true; 535 capSysNice = false; 536 package = gamescope_3_14; 537 }; 538 539 # Manually add the gamescope capability wrapper without triggering 540 # the steam module's setuid bwrap override (which zeros CapBnd 541 # inside the FHS sandbox, preventing games from launching) 542 security.wrappers.gamescope = { 543 owner = "root"; 544 group = "root"; 545 source = "${gamescope_3_14}/bin/gamescope"; 546 capabilities = "cap_sys_nice+pie"; 547 }; 548 549 environment.systemPackages = [ 550 pkgs.lm_sensors 551 bambu-studio 552 steamos-session-select 553 ]; 554 555 # Enable the OpenSSH daemon. 556 # services.openssh.enable = true; 557 558 security.pam.loginLimits = [ 559 { 560 domain = "*"; 561 type = "soft"; 562 item = "nofile"; 563 value = "8192"; 564 } 565 ]; 566 567 # trmnl-rs server 568 systemd.services.trmnl-rs = { 569 description = "TRMNL Server"; 570 wantedBy = [ "multi-user.target" ]; 571 wants = [ "network-online.target" ]; 572 after = [ 573 "network-online.target" 574 "nss-lookup.target" 575 ]; 576 serviceConfig = { 577 ExecStart = "${inputs.trmnl-rs.packages.x86_64-linux.default}/bin/server"; 578 Restart = "on-failure"; 579 RestartSec = 5; 580 DynamicUser = true; 581 StateDirectory = "trmnl-rs"; 582 WorkingDirectory = "/var/lib/trmnl-rs"; 583 }; 584 }; 585 586 # Open ports in the firewall. 587 networking.firewall.allowedTCPPorts = [ 588 8096 # jellyfin 589 5055 # jellyseer 590 3000 # vite dev port 591 1883 # MQTT for Tasmota devices 592 2300 # trmnl 593 5000 # Frigate web UI 594 8971 # Frigate API 595 config.services.home-assistant.config.http.server_port 596 ]; 597 networking.firewall.allowedUDPPorts = [ 598 ]; 599 # networking.firewall.enable = false; 600 601 # This value determines the NixOS release from which the default 602 # settings for stateful data, like file locations and database versions 603 # on your system were taken. It‘s perfectly fine and recommended to leave 604 # this value at the release version of the first install of this system. 605 # Before changing this value read the documentation for this option 606 # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html). 607 system.stateVersion = "25.05"; # Did you read the comment? 608 609}