Rebase to flake parts #10
This commit is contained in:
@@ -752,6 +752,14 @@ in {
|
||||
"trailing_diamond": "\ue0b4",
|
||||
"type": "session"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"style": "diamond",
|
||||
"background": "#3A456E",
|
||||
"foreground": "#ffbebc",
|
||||
"template": "\u007B\u007B if .Env.IN_NIX_SHELL \u007D\u007Din nix-shell\u007B\u007B end \u007D\u007D",
|
||||
"trailing_diamond": "\ue0b4"
|
||||
},
|
||||
{
|
||||
"background": "#3A456E",
|
||||
"foreground": "#bc93ff",
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
# Export large Jellyfin media trees to nix-server. Local path must already exist
|
||||
# (e.g. /mnt/test/jellyfin/{movies,tv}). On nix-server this is mounted at /mnt/nixdesk-jellyfin.
|
||||
# NFS exports from nixdesk (14900k) to nix-server (192.168.2.238):
|
||||
# - /mnt/test/jellyfin → nix-server /mnt/nixdesk-jellyfin (Jellyfin bulk libraries)
|
||||
# - /mnt/media → nix-server /mnt/media (Btrfs MediaLibrary disk; see media-disk.nix)
|
||||
#
|
||||
# After deploy: ensure Jellyfin can read files over NFS — typical fix:
|
||||
# chmod -R a+rX /mnt/test/jellyfin
|
||||
{ ... }:
|
||||
# NTFS on nixdesk uses uid=olivier + gid=nfsmedia (990); dirs here are olivier:nfsmedia 2775 so
|
||||
# local writes and NFS all_squash (anonuid=olivier, anongid=990) get rwx via owner or group.
|
||||
#
|
||||
# Legacy trees may still need a one-time `chgrp -R nfsmedia` / `chmod -R g+rwX` on deep folders.
|
||||
{ config, pkgs, ... }:
|
||||
let
|
||||
olivierUid = config.users.users.olivier.uid or 1000;
|
||||
in
|
||||
{
|
||||
# Avoid UID/GID mismatches across machines: map all NFS writes from nix-server to a single
|
||||
# local system user/group on this server.
|
||||
@@ -14,10 +20,32 @@
|
||||
group = "nfsmedia";
|
||||
};
|
||||
|
||||
systemd.tmpfiles.settings."14900k-jellyfin-media-dirs" = {
|
||||
"/mnt/test/jellyfin"."d" = { mode = "2775"; user = "nfsmedia"; group = "nfsmedia"; };
|
||||
"/mnt/test/jellyfin/movies"."d" = { mode = "2775"; user = "nfsmedia"; group = "nfsmedia"; };
|
||||
"/mnt/test/jellyfin/tv"."d" = { mode = "2775"; user = "nfsmedia"; group = "nfsmedia"; };
|
||||
# olivier: owner for local use; nfsmedia: group matches NTFS gid=990 and NFS all_squash (990).
|
||||
systemd.tmpfiles.settings."14900k-nfs-export-paths" = {
|
||||
"/mnt/test"."d" = { mode = "2775"; user = "olivier"; group = "nfsmedia"; };
|
||||
"/mnt/test/jellyfin"."d" = { mode = "2775"; user = "olivier"; group = "nfsmedia"; };
|
||||
"/mnt/test/jellyfin/movies"."d" = { mode = "2775"; user = "olivier"; group = "nfsmedia"; };
|
||||
"/mnt/test/jellyfin/tv"."d" = { mode = "2775"; user = "olivier"; group = "nfsmedia"; };
|
||||
"/mnt/media"."d" = { mode = "2775"; user = "olivier"; group = "nfsmedia"; };
|
||||
"/mnt/media/Movies"."d" = { mode = "2775"; user = "olivier"; group = "nfsmedia"; };
|
||||
"/mnt/media/TV"."d" = { mode = "2775"; user = "olivier"; group = "nfsmedia"; };
|
||||
"/mnt/media/Videos"."d" = { mode = "2775"; user = "olivier"; group = "nfsmedia"; };
|
||||
};
|
||||
|
||||
# After exports are up, ensure group nfsmedia can write throughout library roots (idempotent;
|
||||
# scoped to library folders only — not whole disks). Runs on each `nixos-rebuild switch`.
|
||||
system.activationScripts.nfs-export-group-write = {
|
||||
deps = [ "specialfs" ];
|
||||
text = ''
|
||||
for d in \
|
||||
/mnt/media/TV /mnt/media/Movies /mnt/media/Videos \
|
||||
/mnt/test/jellyfin/tv /mnt/test/jellyfin/movies
|
||||
do
|
||||
[ -d "$d" ] || continue
|
||||
${pkgs.acl}/bin/setfacl -R -m g:nfsmedia:rwx "$d" 2>/dev/null || true
|
||||
${pkgs.acl}/bin/setfacl -R -d -m g:nfsmedia:rwx "$d" 2>/dev/null || true
|
||||
done
|
||||
'';
|
||||
};
|
||||
|
||||
# Fixed ports so the firewall can allow NFS v3 helpers (see networking.firewall below).
|
||||
@@ -26,9 +54,12 @@
|
||||
mountdPort = 4000;
|
||||
lockdPort = 4001;
|
||||
statdPort = 4002;
|
||||
# fsid= stabilizes file handles across server reboots/remounts of this tree (avoids client ESTALE).
|
||||
# fsid= unique per export tree (avoids client ESTALE when multiple paths are exported).
|
||||
# Squash nix-server clients to olivier:nfsmedia so Jellyfin can write .nfo/posters into
|
||||
# existing olivier-owned library folders (990-only squash was "other" r-x on typical 755 trees).
|
||||
exports = ''
|
||||
/mnt/test/jellyfin 192.168.2.238(rw,sync,no_subtree_check,crossmnt,root_squash,all_squash,anonuid=990,anongid=990,fsid=1)
|
||||
/mnt/test/jellyfin 192.168.2.238(rw,sync,no_subtree_check,crossmnt,root_squash,all_squash,anonuid=${toString olivierUid},anongid=990,fsid=1)
|
||||
/mnt/media 192.168.2.238(rw,sync,no_subtree_check,crossmnt,root_squash,all_squash,anonuid=${toString olivierUid},anongid=990,fsid=2)
|
||||
'';
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# Extra local disks. Declared here, not in hardware.nix (hardware.nix is generated).
|
||||
{ config, lib, ... }:
|
||||
let
|
||||
# Stable UID so NTFS `uid=` matches `users.users.olivier` (override if your account is not 1000).
|
||||
olivierUid = config.users.users.olivier.uid or 1000;
|
||||
in
|
||||
{
|
||||
users.users.olivier.uid = lib.mkDefault 1000;
|
||||
|
||||
fileSystems."/mnt/media" = {
|
||||
device = "/dev/disk/by-uuid/17d8a981-db3b-415e-a0f7-7dbc519e04ab";
|
||||
fsType = "btrfs";
|
||||
options = [
|
||||
"subvol=@"
|
||||
"compress=zstd"
|
||||
"noatime"
|
||||
];
|
||||
};
|
||||
|
||||
# LABEL="Deep Storage Unit". Owner olivier, group nfsmedia (990) so:
|
||||
# - local logins write as user 1000 (owner rwx);
|
||||
# - NFS (all_squash → uid/gid 990) matches group 990 → rwx (see jellyfin-nfs-export).
|
||||
fileSystems."/mnt/test" = {
|
||||
device = "/dev/disk/by-uuid/BC12E55E12E51DE0";
|
||||
fsType = "ntfs-3g";
|
||||
options = [
|
||||
"rw"
|
||||
"force"
|
||||
"uid=${toString olivierUid}"
|
||||
"gid=990"
|
||||
"umask=0002"
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -17,6 +17,7 @@
|
||||
./_private/peripherals.nix
|
||||
# ./_private/printing-epson.nix
|
||||
./_private/displays.nix
|
||||
./_private/media-disk.nix
|
||||
./_private/jellyfin-nfs-export.nix
|
||||
];
|
||||
|
||||
@@ -108,8 +109,13 @@ services.cloudflare-warp.enable = true;
|
||||
# Native install (avoid flatpak sandbox issues for QSV/VAAPI).
|
||||
handbrake
|
||||
|
||||
qbittorrent
|
||||
|
||||
# Diagnostics
|
||||
libva-utils # vainfo
|
||||
vlc
|
||||
element-desktop
|
||||
thunderbird
|
||||
];
|
||||
|
||||
|
||||
@@ -136,6 +142,7 @@ services.cloudflare-warp.enable = true;
|
||||
self.homeManagerModules.wisdomAppsDiscord
|
||||
self.homeManagerModules.wisdomAppsSpotify
|
||||
self.homeManagerModules.wisdomAppsLocalsend
|
||||
self.homeManagerModules.wisdomAppsSpacedrive
|
||||
self.homeManagerModules.wisdomAppsPokeclicker
|
||||
self.homeManagerModules.wisdomDesktopScreenshot
|
||||
self.homeManagerModules.wisdomDesktopGtkQtTheming
|
||||
@@ -171,6 +178,7 @@ services.cloudflare-warp.enable = true;
|
||||
spotify.enable = true;
|
||||
spotify.openDiscoveryFirewall = true;
|
||||
localsend.enable = true;
|
||||
spacedrive.enable = true;
|
||||
pokeclicker.enable = true;
|
||||
};
|
||||
|
||||
|
||||
@@ -7,9 +7,12 @@
|
||||
powerManagement.enable = true;
|
||||
|
||||
# ─────────────────────── logind: lid & power button ───────────────────────
|
||||
# Closing the lid suspends, even on AC — Duet 3 is a tablet, treat it like one.
|
||||
# Short press on power: suspend (matches ChromeOS/iOS); long press: poweroff.
|
||||
# The DMS bar power menu is the way to reboot / shut down explicitly.
|
||||
# Tablet form factor: lid close = suspend (even on AC), short power-press = suspend, long
|
||||
# power-press = poweroff. Niri's own power-key handler must stay disabled — see the
|
||||
# `input.disable-power-key-handling` flag in `_private/touch-tablet.nix` — otherwise niri's
|
||||
# `block` inhibitor on `handle-power-key` pre-empts logind and turns the wake-from-suspend
|
||||
# press (which the EC re-delivers as KEY_POWER) into an immediate re-suspend loop
|
||||
# (https://github.com/niri-wm/niri/issues/2233).
|
||||
services.logind.settings.Login = {
|
||||
HandleLidSwitch = "suspend";
|
||||
HandleLidSwitchExternalPower = "suspend";
|
||||
|
||||
@@ -1,17 +1,10 @@
|
||||
# Host-only: ideapad tablet ergonomics — touchscreen calibration, IIO sensors, virtual keyboard,
|
||||
# and per-session helper daemons (tablet-mode toggle + auto-rotation via iio-sensor-proxy) for both
|
||||
# Niri and Hyprland.
|
||||
# touch-controller resume fix, and per-session helper daemons (tablet-mode toggle + auto-rotation
|
||||
# via iio-sensor-proxy) for both Niri and Hyprland. Lives at the NixOS layer because the hardware
|
||||
# bits are system-wide; the per-compositor autostart hooks are gated on `chiasson.desktop.<wm>.enable`
|
||||
# so they stay dormant if you pick the other session at the greeter.
|
||||
#
|
||||
# Why all of this lives at the *NixOS* layer (not the home-manager catalog under wisdom/):
|
||||
# - The hardware bits (`hardware.sensor.iio.enable`, the udev calibration matrix) are system-wide
|
||||
# and tied to this exact device, so they belong with the host module.
|
||||
# - The compositor helpers run via session-specific autostart hooks (Niri `spawn-at-startup`,
|
||||
# Hyprland `exec-once`); the wiring is gated on the matching `chiasson.desktop.<wm>.enable`,
|
||||
# so picking a different session at the greeter just leaves them dormant.
|
||||
#
|
||||
# Two compositor flavours of each daemon:
|
||||
# - Hyprland (CW transforms via `hyprctl`) — original; matches the old NixOS-New setup.
|
||||
# - Niri (CCW transforms via `niri msg output`) — needed because Niri is the V2 default.
|
||||
# Hyprland uses CW transforms via `hyprctl`; Niri uses CCW transforms via `niri msg output`.
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
@@ -268,15 +261,33 @@ in
|
||||
# ─────────────────────── Hardware ───────────────────────
|
||||
hardware.sensor.iio.enable = true;
|
||||
|
||||
# Touchscreen calibration — solved empirically with `niri msg output DSI-1 transform normal`
|
||||
# in the natural kb-down pose. The panel's touch hardware reports raw coordinates already
|
||||
# aligned with the panel-native frame (HW(visual_top_left) = (0,0), etc.), so identity is
|
||||
# correct. `niri input.touch.map-to-output = "DSI-1"` then handles per-orientation rotation
|
||||
# on top — never re-tune this matrix per orientation; rotate the *output* instead.
|
||||
# Touchscreen calibration — identity matrix is correct: hardware coordinates are already aligned
|
||||
# with the panel-native frame, and per-orientation rotation is handled by `niri msg output`,
|
||||
# not by re-tuning this matrix. Rotate the *output*, never this matrix.
|
||||
services.udev.extraRules = ''
|
||||
SUBSYSTEM=="input", ENV{ID_INPUT_TOUCHSCREEN}=="1", ENV{LIBINPUT_CALIBRATION_MATRIX}="1 0 0 0 1 0"
|
||||
'';
|
||||
|
||||
# ─────────────────────── Touch controller resume fix ───────────────────────
|
||||
# The hid-over-i2c touch controller at i2c bus 4-0001 wedges across S3 suspend: after resume it
|
||||
# re-enumerates with the correct capabilities but reports zero events on touch. Cycling the
|
||||
# `i2c_hid_of` driver (unbind + bind) un-wedges it. systemd-sleep runs every executable in
|
||||
# `/etc/systemd/system-sleep/` with `$1 = pre|post`; we only act on `post`. Driver name is
|
||||
# discovered at runtime so a future kernel rename to `i2c_hid` doesn't break this.
|
||||
environment.etc."systemd/system-sleep/ideapad-touch-rebind".source =
|
||||
pkgs.writeShellScript "ideapad-touch-rebind" ''
|
||||
set -eu
|
||||
[ "$1" = post ] || exit 0
|
||||
dev=4-0001
|
||||
dev_dir=/sys/bus/i2c/devices/$dev
|
||||
[ -L "$dev_dir/driver" ] || exit 0
|
||||
drv=$(${pkgs.coreutils}/bin/basename "$(${pkgs.coreutils}/bin/readlink "$dev_dir/driver")")
|
||||
echo "ideapad-touch-rebind: cycling $drv for $dev" >&2
|
||||
echo "$dev" > "/sys/bus/i2c/drivers/$drv/unbind" || true
|
||||
${pkgs.coreutils}/bin/sleep 0.3
|
||||
echo "$dev" > "/sys/bus/i2c/drivers/$drv/bind"
|
||||
'';
|
||||
|
||||
# ─────────────────────── User-facing tools ───────────────────────
|
||||
# System-wide so any user session (Niri or Hyprland) can launch wvkbd / hyprctl / niri-msg helpers.
|
||||
environment.systemPackages = [
|
||||
@@ -297,6 +308,12 @@ in
|
||||
chiasson.desktop.niri.extraSettings = lib.mkIf config.chiasson.desktop.niri.enable {
|
||||
input.touch.map-to-output = "DSI-1";
|
||||
|
||||
# Required for logind's `HandlePowerKey` in `_private/platform.nix` to take effect: otherwise
|
||||
# niri grabs a `block` inhibitor on `handle-power-key` and suspends via D-Bus, including on
|
||||
# the EC's wake-from-suspend KEY_POWER event → instant re-suspend loop.
|
||||
# https://github.com/niri-wm/niri/issues/2233
|
||||
input."disable-power-key-handling" = _: { };
|
||||
|
||||
# wrapper-modules schema: each entry is a `command argv` list of strings (or a single string).
|
||||
spawn-at-startup = [
|
||||
[ "ideapad-niri-autorotate-daemon" ]
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
{ self, inputs, ... }: {
|
||||
|
||||
# Lenovo Chromebook Duet 3 (`lenovo-wormdingler`) on Mobile NixOS.
|
||||
#
|
||||
# Phase 1 (minimal bootstrap) lived here previously; we now run the full V2 stack:
|
||||
# mobile-nixos device + Niri/Hyprland/DMS, DankGreeter, Waydroid (tablet-class), wvkbd,
|
||||
# IIO sensors, touchscreen calibration, attic cache, sops, and the standard user catalog.
|
||||
# Full V2 stack: mobile-nixos device + Niri/Hyprland/DMS, DankGreeter, wvkbd, IIO sensors,
|
||||
# touchscreen calibration + resume-rebind, attic cache, sops, and the standard user catalog.
|
||||
# Host-only quirks live in `_private/touch-tablet.nix` and `_private/platform.nix`.
|
||||
flake.nixosModules.ideapadConfiguration =
|
||||
{
|
||||
self,
|
||||
@@ -102,9 +101,8 @@
|
||||
};
|
||||
|
||||
# ─────────────────────── Desktop ───────────────────────
|
||||
# Both compositors enabled; DankGreeter lets you pick at login. Default = Niri (V2 convention),
|
||||
# Hyprland session is where the tablet-mode + autorotate daemons in `_private/touch-tablet.nix`
|
||||
# actually run (they hook `exec-once`).
|
||||
# Both compositors are enabled — DankGreeter picks at login, V2 default is Niri.
|
||||
# Per-session tablet-mode / autorotate daemons live in `_private/touch-tablet.nix`.
|
||||
chiasson.desktop = {
|
||||
niri.enable = true;
|
||||
hyprland.enable = true;
|
||||
@@ -113,6 +111,7 @@
|
||||
shell = "dms";
|
||||
shells.dms = {
|
||||
enableWvkbdToggle = true;
|
||||
enableRbwLockToggle = true;
|
||||
# Cross-build on the 14900k via binfmt and push back over LAN — much faster than
|
||||
# rebuilding aarch64 closure on the Snapdragon. Mirrors the old NixOS-New flow:
|
||||
# ssh out to nixdesk, run nixos-rebuild --target-host pointing back at us.
|
||||
@@ -126,15 +125,6 @@
|
||||
];
|
||||
};
|
||||
|
||||
# Tablet-class screen → constrain Waydroid to a sane portrait-ish frame and use gesture nav
|
||||
# instead of 3-button so it feels like the ChromeOS tablet UI.
|
||||
#waydroid = {
|
||||
# enable = true;
|
||||
# multiWindows = false;
|
||||
# width = 1600;
|
||||
# height = 960;
|
||||
# navigationMode = "gestures";
|
||||
#};
|
||||
};
|
||||
|
||||
# ─────────────────────── Users / HM ───────────────────────
|
||||
@@ -146,10 +136,12 @@
|
||||
self.homeManagerModules.wisdomTerminalsKitty
|
||||
self.homeManagerModules.wisdomBrowsersZen
|
||||
self.homeManagerModules.wisdomEditorsKate
|
||||
self.homeManagerModules.wisdomEditorsCursor
|
||||
self.homeManagerModules.wisdomShellFish
|
||||
self.homeManagerModules.wisdomShellOhMyPosh
|
||||
self.homeManagerModules.wisdomAppsSpotify
|
||||
self.homeManagerModules.wisdomAppsLocalsend
|
||||
self.homeManagerModules.wisdomAppsSpacedrive
|
||||
self.homeManagerModules.wisdomDesktopScreenshot
|
||||
{
|
||||
chiasson.home = {
|
||||
@@ -161,8 +153,10 @@
|
||||
filebrowsers.dolphin.enable = true;
|
||||
browsers.zen.enable = true;
|
||||
editors.kate.enable = true;
|
||||
editors.cursor.enable = true;
|
||||
apps.spotify.enable = true;
|
||||
apps.localsend.enable = true;
|
||||
apps.spacedrive.enable = true;
|
||||
desktop = {
|
||||
screenshot = {
|
||||
enable = true;
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# Dispatcharr — IPTV / M3U / EPG / HDHomeRun-style proxy (Docker, AIO image).
|
||||
# Docs: https://dispatcharr.github.io/Dispatcharr-Docs/
|
||||
# Compose reference: https://github.com/Dispatcharr/Dispatcharr/blob/main/docker/docker-compose.aio.yml
|
||||
#
|
||||
# Web UI: http://<host>:9191
|
||||
# After deploy: create an admin user, add playlists / EPG; point Jellyfin at the tuner/M3U URLs
|
||||
# Dispatcharr shows in its UI.
|
||||
{ lib, pkgs, ... }:
|
||||
{
|
||||
systemd.tmpfiles.settings."nix-server-dispatcharr-data" = {
|
||||
"/var/lib/dispatcharr"."d" = {
|
||||
mode = "0755";
|
||||
user = "root";
|
||||
group = "root";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.docker-dispatcharr.preStart = lib.mkBefore ''
|
||||
${pkgs.coreutils}/bin/mkdir -p /var/lib/dispatcharr
|
||||
'';
|
||||
|
||||
virtualisation.oci-containers.containers.dispatcharr = {
|
||||
image = "ghcr.io/dispatcharr/dispatcharr:latest";
|
||||
ports = [ "9191:9191" ];
|
||||
volumes = [
|
||||
"/var/lib/dispatcharr:/data"
|
||||
];
|
||||
environment = {
|
||||
DISPATCHARR_ENV = "aio";
|
||||
REDIS_HOST = "localhost";
|
||||
CELERY_BROKER_URL = "redis://localhost:6379/0";
|
||||
DISPATCHARR_LOG_LEVEL = "info";
|
||||
TZ = "America/Moncton";
|
||||
};
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [ 9191 ];
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
# NFS read-only mount of nixdesk (14900k) bulk storage for extra Jellyfin libraries.
|
||||
# Source: ssh inventory hostName for 14900k. Export is defined in
|
||||
# modules/hosts/14900k/_private/jellyfin-nfs-export.nix
|
||||
#
|
||||
# In Jellyfin (in addition to local /var/lib/media/...), add e.g.:
|
||||
# Movies → /mnt/nixdesk-jellyfin/movies
|
||||
# Shows → /mnt/nixdesk-jellyfin/tv
|
||||
{ ... }:
|
||||
let
|
||||
# Must match LAN IP of the NFS server (flake `sshInventory` → hosts."14900k".hostName).
|
||||
nfsExportHost = "192.168.2.25";
|
||||
in
|
||||
{
|
||||
fileSystems."/mnt/nixdesk-jellyfin" = {
|
||||
device = "${nfsExportHost}:/mnt/test/jellyfin";
|
||||
fsType = "nfs";
|
||||
options = [
|
||||
"rw"
|
||||
"noatime"
|
||||
"nofail"
|
||||
"_netdev"
|
||||
"x-systemd.automount"
|
||||
"x-systemd.idle-timeout=600"
|
||||
];
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
# Jellyfin (native NixOS service). Local media: /var/lib/media (group `media`; jellyfin + server).
|
||||
# Dashboard: Movies → /var/lib/media/movies, Shows → /var/lib/media/tv (see jellyfin-remote-storage.nix
|
||||
# Dashboard: Movies → /var/lib/media/movies, Shows → /var/lib/media/tv (see nixdesk-nfs-client.nix
|
||||
# for bulk libraries on nixdesk at /mnt/nixdesk-jellyfin/{movies,tv}).
|
||||
# Do not use "Mixed Movies and Shows" (deprecated): https://jellyfin.org/docs/general/server/media/mixed-movies-and-shows
|
||||
# Dedicated disk: fileSystems."/var/lib/media" in hardware.nix, then fix ownership.
|
||||
@@ -53,8 +53,9 @@
|
||||
# not writable by uid jellyfin (it only had group `jellyfin`), so deletes fail.
|
||||
systemd.services.jellyfin.serviceConfig = {
|
||||
SupplementaryGroups = [ "media" ];
|
||||
# Jellyfin libraries may live on NFS (e.g. /mnt/nixdesk-jellyfin). PrivateUsers breaks
|
||||
# uid mapping for NFS auth in practice; disable so deletes use the real host jellyfin uid.
|
||||
# Jellyfin libraries on NFS (e.g. /mnt/media, /mnt/nixdesk-jellyfin). PrivateUsers breaks
|
||||
# uid mapping for NFS auth in practice; disable so metadata writes use the real jellyfin uid
|
||||
# (squashed to olivier:nfsmedia on nixdesk exports).
|
||||
PrivateUsers = lib.mkForce false;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
# NFS mounts of nixdesk (14900k) bulk storage for nix-server. Exports live in
|
||||
# modules/hosts/14900k/_private/jellyfin-nfs-export.nix
|
||||
#
|
||||
# Jellyfin library paths (see also services/jellyfin.nix):
|
||||
# Movies → /mnt/nixdesk-jellyfin/movies
|
||||
# Shows → /mnt/nixdesk-jellyfin/tv
|
||||
#
|
||||
# If you see "Stale file handle" under /mnt after changing exports or fsid on nixdesk, drop the
|
||||
# old client mount and let automount reattach, e.g.:
|
||||
# sudo umount -l /mnt/nixdesk-jellyfin
|
||||
# ls /mnt/nixdesk-jellyfin
|
||||
# (or reboot nix-server.)
|
||||
{ ... }:
|
||||
let
|
||||
nfsExportHost = "192.168.2.25";
|
||||
# nfsvers+tcp: predictable Linux↔Linux; lookupcache=none: fewer stale dentries after export changes.
|
||||
nfsClientOpts = [
|
||||
"rw"
|
||||
"noatime"
|
||||
"nofail"
|
||||
"_netdev"
|
||||
"nfsvers=3"
|
||||
"tcp"
|
||||
"lookupcache=none"
|
||||
"x-systemd.automount"
|
||||
"x-systemd.idle-timeout=3600"
|
||||
];
|
||||
in
|
||||
{
|
||||
fileSystems."/mnt/nixdesk-jellyfin" = {
|
||||
device = "${nfsExportHost}:/mnt/test/jellyfin";
|
||||
fsType = "nfs";
|
||||
options = nfsClientOpts;
|
||||
};
|
||||
|
||||
fileSystems."/mnt/media" = {
|
||||
device = "${nfsExportHost}:/mnt/media";
|
||||
fsType = "nfs";
|
||||
options = nfsClientOpts;
|
||||
};
|
||||
}
|
||||
@@ -20,7 +20,7 @@
|
||||
./_services/swiftshare.nix
|
||||
./_services/immich.nix
|
||||
./_services/jellyfin.nix
|
||||
./_services/jellyfin-remote-storage.nix
|
||||
./_services/nixdesk-nfs-client.nix
|
||||
./_services/ddrm-media-server.nix
|
||||
./_services/sonarr.nix
|
||||
./_services/prowlarr.nix
|
||||
@@ -28,6 +28,7 @@
|
||||
./_services/radarr.nix
|
||||
./_services/qbittorrent.nix
|
||||
./_services/seerr.nix
|
||||
./_services/dispatcharr.nix
|
||||
];
|
||||
|
||||
boot.loader.grub = {
|
||||
|
||||
@@ -95,6 +95,9 @@
|
||||
};
|
||||
defaultSession = "niri";
|
||||
shell = "dms";
|
||||
shells.dms = {
|
||||
enableRbwLockToggle = true;
|
||||
};
|
||||
};
|
||||
|
||||
chiasson.system = {
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
{ config, ... }:
|
||||
{
|
||||
# cockpit-file-sharing expects a live Samba stack: /etc/samba/smb.conf, smbd, and
|
||||
# `include = registry` in [global] for net registry share management.
|
||||
services.samba = {
|
||||
enable = true;
|
||||
openFirewall = true;
|
||||
winbindd.enable = false;
|
||||
settings.global = {
|
||||
workgroup = "WORKGROUP";
|
||||
"server string" = config.networking.hostName;
|
||||
include = "registry";
|
||||
};
|
||||
};
|
||||
|
||||
services.nfs.server = {
|
||||
enable = true;
|
||||
mountdPort = 4000;
|
||||
lockdPort = 4001;
|
||||
statdPort = 4002;
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [
|
||||
111
|
||||
2049
|
||||
4000
|
||||
4001
|
||||
4002
|
||||
];
|
||||
networking.firewall.allowedUDPPorts = [
|
||||
111
|
||||
2049
|
||||
4000
|
||||
4001
|
||||
4002
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
{
|
||||
acl,
|
||||
bash,
|
||||
coreutils,
|
||||
dpkg,
|
||||
fetchurl,
|
||||
findutils,
|
||||
hostname,
|
||||
iproute2,
|
||||
jq,
|
||||
lib,
|
||||
nfs-utils,
|
||||
python3Packages,
|
||||
samba,
|
||||
stdenv,
|
||||
systemd,
|
||||
}:
|
||||
|
||||
stdenv.mkDerivation {
|
||||
pname = "cockpit-file-sharing";
|
||||
version = "4.5.6-1";
|
||||
|
||||
src = fetchurl {
|
||||
url = "https://github.com/45Drives/cockpit-file-sharing/releases/download/v4.5.6-1/cockpit-file-sharing_4.5.6-1jammy_all.deb";
|
||||
hash = "sha256-ViTdhiCmqwuBvAfzT8hr2kqZqyWkV9OZ9FEPD10ajF8=";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [ dpkg ];
|
||||
|
||||
unpackPhase = "dpkg-deb -x $src source";
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
mkdir -p $out/share/cockpit
|
||||
cp -r source/usr/share/cockpit/file-sharing $out/share/cockpit/
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
passthru.cockpitPath = [
|
||||
acl
|
||||
bash
|
||||
coreutils
|
||||
findutils
|
||||
hostname
|
||||
iproute2
|
||||
jq
|
||||
nfs-utils
|
||||
python3Packages.botocore
|
||||
samba
|
||||
systemd
|
||||
];
|
||||
|
||||
meta = {
|
||||
description = "Cockpit plugin to manage Samba and NFS file sharing (45Drives)";
|
||||
homepage = "https://github.com/45Drives/cockpit-file-sharing";
|
||||
license = lib.licenses.gpl3Plus;
|
||||
platforms = lib.platforms.linux;
|
||||
sourceProvenance = with lib.sourceTypes; [ binaryNativeCode ];
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{ config, pkgs, ... }:
|
||||
let
|
||||
cockpitFileSharing = pkgs.callPackage ./cockpit-file-sharing/package.nix { };
|
||||
in
|
||||
{
|
||||
imports = [ ./cockpit-file-sharing-services.nix ];
|
||||
|
||||
services.cockpit = {
|
||||
enable = true;
|
||||
openFirewall = true;
|
||||
allowed-origins = [
|
||||
"https://${config.networking.hostName}:${toString config.services.cockpit.port}"
|
||||
"https://192.168.2.60:${toString config.services.cockpit.port}"
|
||||
];
|
||||
plugins = with pkgs; [
|
||||
cockpit-files
|
||||
cockpit-machines
|
||||
cockpit-podman
|
||||
cockpitFileSharing
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
# Pi 5 / CM5 onboard Wi-Fi (brcmfmac). Without a regulatory domain the driver scans
|
||||
# disallowed channels and spams: brcmf_set_channel: set chanspec … fail, reason -52
|
||||
# (open raspberrypi/linux#6049). Wi-Fi often still works; logs and scans are noisy.
|
||||
{ pkgs, ... }:
|
||||
let
|
||||
wifiCountry = "CA"; # change if you are not in Canada
|
||||
in
|
||||
{
|
||||
boot.kernelParams = [
|
||||
"cfg80211.ieee80211_regdom=${wifiCountry}"
|
||||
];
|
||||
|
||||
# Firmware country code (config.txt) — picked up before userspace regdom.
|
||||
hardware.raspberry-pi.extra-config = ''
|
||||
country=${wifiCountry}
|
||||
'';
|
||||
|
||||
# Apply regdom before NetworkManager starts scanning.
|
||||
systemd.services.wifi-regulatory-domain = {
|
||||
description = "Set Wi-Fi regulatory domain for brcmfmac";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
before = [ "NetworkManager.service" ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
};
|
||||
script = ''
|
||||
${pkgs.iw}/bin/iw reg set ${wifiCountry}
|
||||
'';
|
||||
};
|
||||
|
||||
networking.networkmanager.wifi.powersave = false;
|
||||
networking.networkmanager.wifi.scanRandMacAddress = false;
|
||||
networking.networkmanager.connectionConfig."wifi.bgscan" = "0";
|
||||
}
|
||||
@@ -29,7 +29,9 @@
|
||||
|
||||
self.nixosModules."client-services"
|
||||
./_private/platform.nix
|
||||
./_private/wifi-brcmfmac.nix
|
||||
./_private/services.nix
|
||||
./_private/cockpit.nix
|
||||
./_private/activation.nix
|
||||
./_private/4g/default.nix
|
||||
];
|
||||
|
||||
@@ -19,6 +19,14 @@
|
||||
}) names
|
||||
);
|
||||
inboundUsersAttr = usersLib.inboundHostsAttr selected;
|
||||
|
||||
# HM configures fish in ~/.config/fish but no longer sets /etc/passwd or /etc/shells.
|
||||
hmFishUsers =
|
||||
if !hmAvailable then { }
|
||||
else
|
||||
lib.filterAttrs (
|
||||
name: hmUser: (hmUser.programs.fish.enable or false) && builtins.elem name names
|
||||
) config.home-manager.users;
|
||||
in
|
||||
{
|
||||
config = lib.mkMerge [
|
||||
@@ -46,6 +54,18 @@
|
||||
chiasson.ssh.inbound.enable = true;
|
||||
chiasson.ssh.inbound.userAuthorizedHosts = inboundUsersAttr;
|
||||
})
|
||||
(lib.mkIf (hmFishUsers != { }) {
|
||||
environment.shells = lib.mkAfter (
|
||||
lib.mapAttrsToList (
|
||||
_: hmUser: lib.getExe hmUser.programs.fish.package
|
||||
) hmFishUsers
|
||||
);
|
||||
users.users = lib.mapAttrs (
|
||||
name: hmUser: {
|
||||
shell = lib.mkForce (lib.getExe hmUser.programs.fish.package);
|
||||
}
|
||||
) hmFishUsers;
|
||||
})
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
{ ... }: {
|
||||
flake.homeManagerModules.wisdomAppsSpacedrive =
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
root = config.chiasson.home;
|
||||
cfg = config.chiasson.home.apps.spacedrive;
|
||||
spacedrivePkg = pkgs.callPackage ./package { };
|
||||
in
|
||||
{
|
||||
options.chiasson.home.apps.spacedrive = {
|
||||
enable = lib.mkEnableOption ''
|
||||
[Spacedrive](https://spacedrive.com/) v2 alpha — upstream `.deb` repackaged for NixOS.
|
||||
'';
|
||||
|
||||
package = lib.mkOption {
|
||||
type = lib.types.package;
|
||||
default = spacedrivePkg;
|
||||
description = "Spacedrive package (defaults to upstream v2.0.0-alpha.2).";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf (root.enable && cfg.enable) {
|
||||
home.packages = [ cfg.package ];
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
{
|
||||
lib,
|
||||
stdenv,
|
||||
fetchurl,
|
||||
dpkg,
|
||||
makeWrapper,
|
||||
autoPatchelfHook,
|
||||
wrapGAppsHook3,
|
||||
adwaita-icon-theme,
|
||||
ffmpeg,
|
||||
gdk-pixbuf,
|
||||
glib,
|
||||
glib-networking,
|
||||
gst_all_1,
|
||||
gtk3,
|
||||
hicolor-icon-theme,
|
||||
libsoup_3,
|
||||
webkitgtk_4_1,
|
||||
xdotool,
|
||||
}:
|
||||
|
||||
let
|
||||
version = "2.0.0-alpha.2";
|
||||
|
||||
srcInfo =
|
||||
if stdenv.hostPlatform.system == "x86_64-linux" then
|
||||
{
|
||||
url = "https://github.com/spacedriveapp/spacedrive/releases/download/v${version}/Spacedrive-linux-x86_64.deb";
|
||||
hash = "sha256-KzRPBtyX5x4ZLlZd6SgAS/cy/7irXt7v+b3Yuq9GETo=";
|
||||
}
|
||||
else if stdenv.hostPlatform.system == "aarch64-linux" then
|
||||
{
|
||||
url = "https://github.com/spacedriveapp/spacedrive/releases/download/v${version}/Spacedrive-linux-aarch64.deb";
|
||||
hash = "sha256-Arq4seJxd69XdraIaYJSv1p9g+Bz/7rez/l9EP6dc9k=";
|
||||
}
|
||||
else
|
||||
throw "spacedrive ${version}: unsupported platform: ${stdenv.hostPlatform.system}";
|
||||
in
|
||||
stdenv.mkDerivation {
|
||||
pname = "spacedrive";
|
||||
inherit version;
|
||||
|
||||
src = fetchurl srcInfo;
|
||||
|
||||
nativeBuildInputs = [
|
||||
dpkg
|
||||
makeWrapper
|
||||
autoPatchelfHook
|
||||
wrapGAppsHook3
|
||||
];
|
||||
|
||||
buildInputs = [
|
||||
adwaita-icon-theme
|
||||
ffmpeg
|
||||
gdk-pixbuf
|
||||
glib
|
||||
glib-networking
|
||||
gtk3
|
||||
hicolor-icon-theme
|
||||
libsoup_3
|
||||
webkitgtk_4_1
|
||||
xdotool
|
||||
gst_all_1.gst-plugins-ugly
|
||||
gst_all_1.gst-plugins-bad
|
||||
gst_all_1.gst-plugins-base
|
||||
gst_all_1.gstreamer
|
||||
];
|
||||
|
||||
# WebKitGTK + TLS + icons; ffmpeg/ffprobe on PATH (alpha Linux builds omit bundled ffmpeg).
|
||||
preFixup = ''
|
||||
gappsWrapperArgs+=(
|
||||
"--prefix" "PATH" ":" "${lib.makeBinPath [ ffmpeg ]}"
|
||||
"--set-default" "WEBKIT_DISABLE_DMABUF_RENDERER" "1"
|
||||
)
|
||||
'';
|
||||
|
||||
postFixup = ''
|
||||
# Core daemon is not GTK-linked; wrapGAppsHook3 skips it — still needs ffmpeg for media paths.
|
||||
wrapProgram $out/bin/sd-daemon --prefix PATH : "${lib.makeBinPath [ ffmpeg ]}"
|
||||
'';
|
||||
|
||||
unpackPhase = "dpkg-deb -x $src source";
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
mkdir -p $out/{bin,lib,share}
|
||||
cp -r source/usr/bin/* $out/bin/
|
||||
cp -r source/usr/lib/* $out/lib/
|
||||
cp -r source/usr/share/* $out/share/
|
||||
|
||||
ln -sf Spacedrive $out/bin/spacedrive
|
||||
|
||||
substituteInPlace $out/share/applications/Spacedrive.desktop \
|
||||
--replace-fail 'Exec=Spacedrive' 'Exec=spacedrive'
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
meta = with lib; {
|
||||
description = "Local-first file manager and virtual distributed filesystem (v2 alpha)";
|
||||
homepage = "https://spacedrive.com";
|
||||
changelog = "https://github.com/spacedriveapp/spacedrive/releases/tag/v${version}";
|
||||
license = licenses.agpl3Plus;
|
||||
platforms = [
|
||||
"x86_64-linux"
|
||||
"aarch64-linux"
|
||||
];
|
||||
mainProgram = "spacedrive";
|
||||
sourceProvenance = with sourceTypes; [ binaryNativeCode ];
|
||||
};
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
imports = [
|
||||
./apps/discord.nix
|
||||
./apps/localsend.nix
|
||||
./apps/spacedrive
|
||||
./apps/pokeclicker
|
||||
./apps/spotify.nix
|
||||
./browsers/orion.nix
|
||||
|
||||
@@ -6,7 +6,17 @@
|
||||
cfg = config.chiasson.home.shell.fish;
|
||||
in
|
||||
{
|
||||
options.chiasson.home.shell.fish.enable = lib.mkEnableOption "Fish + grc, quiet greeting, rbw SSH socket defaults.";
|
||||
options.chiasson.home.shell.fish = {
|
||||
enable = lib.mkEnableOption "Fish + grc, quiet greeting, rbw SSH socket defaults.";
|
||||
|
||||
nixYourShell = {
|
||||
enable = lib.mkEnableOption ''
|
||||
Wrap `nix` / `nix-shell` so ephemeral shells use fish (and keep oh-my-posh) instead of bash.
|
||||
'' // {
|
||||
default = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf (root.enable && cfg.enable) {
|
||||
# `fishPlugins.grc` only installs the plugin; the wrapper invokes the `grc` binary.
|
||||
@@ -32,6 +42,11 @@
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
programs.nix-your-shell = lib.mkIf cfg.nixYourShell.enable {
|
||||
enable = true;
|
||||
enableFishIntegration = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user