me like nix
0

Configure Feed

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

1{ inputs, ... }: 2 3let 4 jellyfinKodiSyncQueue = inputs.nixpkgs.legacyPackages.x86_64-linux.fetchzip { 5 url = "https://repo.jellyfin.org/releases/plugin/kodi-sync-queue/kodi-sync-queue_15.0.0.0.zip"; 6 stripRoot = false; 7 hash = "sha256-xtlG3UQ/WClt/Hvxe+oId2CeJ+PWMDXBUJXh5+k+mZQ="; 8 }; 9in 10{ 11 flake.modules.nixos.media-server = 12 { pkgs, config, lib, ... }: 13 { 14 services.flaresolverr.enable = true; 15 16 services.immich = { 17 enable = true; 18 mediaLocation = "/mnt/storage2/immich"; 19 host = "0.0.0.0"; 20 openFirewall = true; 21 }; 22 23 # Immich uses PostgreSQL via Unix socket; avoid conflicting with lbdt-postgres on TCP/5432. 24 services.postgresql.settings.listen_addresses = lib.mkForce ""; 25 26 systemd.tmpfiles.rules = [ 27 "d /mnt/storage2/immich 0750 immich immich -" 28 ]; 29 30 # transmission.service bind-mounts these paths before ExecStartPre runs, while 31 # systemd-tmpfiles refuses to create them because /mnt/storage1 is user-owned. 32 # Create them in a small unsandboxed dependency before Transmission starts. 33 systemd.services.transmission-media-dirs = { 34 description = "Create Transmission media directories"; 35 before = [ "transmission.service" ]; 36 requiredBy = [ "transmission.service" ]; 37 serviceConfig = { 38 Type = "oneshot"; 39 RemainAfterExit = true; 40 }; 41 script = '' 42 install -d -o transmission -g media -m 0755 \ 43 /mnt/storage1/nixarr/media/torrents \ 44 /mnt/storage1/nixarr/media/torrents/.incomplete \ 45 /mnt/storage1/nixarr/media/torrents/.watch 46 ''; 47 }; 48 systemd.services.transmission = { 49 requires = [ "transmission-media-dirs.service" ]; 50 after = [ "transmission-media-dirs.service" ]; 51 }; 52 53 # Keep manually-created Sonarr/Radarr SABnzbd download clients in sync with 54 # SABnzbd's generated API key. This avoids storing the SABnzbd API key in Nix 55 # while repairing clients after the settings-backed SABnzbd config rewrite. 56 systemd.services.sync-sabnzbd-download-client-keys = { 57 description = "Sync SABnzbd API key into Arr download clients"; 58 after = [ "sabnzbd.service" "sonarr.service" "radarr.service" ]; 59 wants = [ "sabnzbd.service" "sonarr.service" "radarr.service" ]; 60 wantedBy = [ "multi-user.target" ]; 61 serviceConfig = { 62 Type = "oneshot"; 63 User = "root"; 64 }; 65 path = [ pkgs.python3 ]; 66 script = '' 67 python3 ${pkgs.writeText "sync-sabnzbd-download-client-keys.py" '' 68 import json 69 import urllib.error 70 import urllib.request 71 from pathlib import Path 72 73 def read_key(path): 74 for line in Path(path).read_text().splitlines(): 75 if line.strip().startswith("api_key"): 76 return line.split("=", 1)[1].strip() 77 raise RuntimeError(f"api_key not found in {path}") 78 79 sab_key = read_key("/var/lib/sabnzbd/sabnzbd.ini") 80 81 services = [ 82 ("Sonarr", "http://127.0.0.1:8989", "/data/.state/nixarr/secrets/sonarr.api-key"), 83 ("Radarr", "http://127.0.0.1:7878", "/data/.state/nixarr/secrets/radarr.api-key"), 84 ] 85 86 def request(base, api_key, method, path, data=None): 87 body = None if data is None else json.dumps(data).encode() 88 req = urllib.request.Request( 89 base + path, 90 data=body, 91 method=method, 92 headers={"X-Api-Key": api_key, "Content-Type": "application/json"}, 93 ) 94 with urllib.request.urlopen(req, timeout=10) as resp: 95 raw = resp.read() 96 return None if not raw else json.loads(raw) 97 98 for name, base, key_file in services: 99 try: 100 api_key = Path(key_file).read_text().strip() 101 clients = request(base, api_key, "GET", "/api/v3/downloadclient") 102 changed = 0 103 for client in clients: 104 if (client.get("implementation") or "").lower() != "sabnzbd" and (client.get("name") or "").lower() != "sabnzbd": 105 continue 106 for field in client.get("fields", []): 107 if field.get("name") == "apiKey" and field.get("value") != sab_key: 108 field["value"] = sab_key 109 changed += 1 110 request(base, api_key, "PUT", f"/api/v3/downloadclient/{client['id']}", client) 111 print(f"{name}: updated {changed} SABnzbd apiKey field(s)") 112 except Exception as e: 113 print(f"{name}: failed to sync SABnzbd API key: {e}") 114 raise 115 ''} 116 ''; 117 }; 118 119 # nixarr configures SABnzbd through services.sabnzbd.settings on newer nixpkgs, 120 # but NixOS keeps the legacy configFile default when system.stateVersion < 26.05, 121 # causing those settings to be ignored. Force the new settings-backed path. 122 services.sabnzbd.configFile = lib.mkForce null; 123 124 age.secrets.wireguard.file = ../secrets/wireguard.age; 125 126 nixarr = { 127 enable = true; 128 mediaDir = "/mnt/storage1/nixarr/media"; 129 vpn = { 130 enable = true; 131 wgConf = config.age.secrets.wireguard.path; 132 }; 133 134 jellyfin = { 135 enable = true; 136 openFirewall = true; 137 }; 138 139 transmission = { 140 enable = true; 141 vpn.enable = true; 142 peerPort = 51413; 143 }; 144 sabnzbd = { 145 enable = true; 146 vpn.enable = true; 147 openFirewall = true; 148 }; 149 150 prowlarr.enable = true; 151 radarr.enable = true; 152 sonarr.enable = true; 153 seerr = { 154 enable = true; 155 openFirewall = true; 156 }; 157 158 recyclarr = { 159 enable = true; 160 configuration = { 161 sonarr = { 162 series = { 163 base_url = "http://localhost:8989"; 164 api_key = "!env_var SONARR_API_KEY"; 165 quality_definition = { 166 type = "series"; 167 }; 168 delete_old_custom_formats = true; 169 custom_formats = [ 170 { 171 trash_ids = [ 172 "85c61753df5da1fb2aab6f2a47426b09" 173 "9c11cd3f07101cdba90a2d81cf0e56b4" 174 ]; 175 assign_scores_to = [ 176 { 177 name = "WEB-DL (1080p)"; 178 score = -10000; 179 } 180 ]; 181 } 182 ]; 183 }; 184 }; 185 radarr = { 186 movies = { 187 base_url = "http://localhost:7878"; 188 api_key = "!env_var RADARR_API_KEY"; 189 quality_definition = { 190 type = "movie"; 191 }; 192 delete_old_custom_formats = true; 193 custom_formats = [ 194 { 195 trash_ids = [ 196 "570bc9ebecd92723d2d21500f4be314c" 197 "eca37840c13c6ef2dd0262b141a5482f" 198 ]; 199 assign_scores_to = [ 200 { 201 name = "HD Bluray + WEB"; 202 score = 25; 203 } 204 ]; 205 } 206 ]; 207 }; 208 }; 209 }; 210 }; 211 }; 212 213 # Avoid jellyfin blocking shutdown for 2 minutes 214 systemd.services.jellyfin.serviceConfig.TimeoutStopSec = 10; 215 216 # Install Kodi Sync Queue plugin into Jellyfin 217 systemd.services.jellyfin.serviceConfig.ExecStartPre = 218 let 219 pluginDir = "/data/.state/nixarr/jellyfin/data/plugins/Kodi Sync Queue/15.0.0.0"; 220 in 221 pkgs.writeShellScript "install-jellyfin-plugins" '' 222 mkdir -p "${pluginDir}" 223 cp -f ${jellyfinKodiSyncQueue}/*.dll ${jellyfinKodiSyncQueue}/meta.json "${pluginDir}/" 224 ''; 225 }; 226}