OOKNET                             [ /  search the index  ]  
──────────────────────────────────────────────────────────────────────────────────────
══════════════════════════════════════════════════════════════════════════════════════
OOKNET   [ /  search  ]  
────────────────────────────────────────────────
════════════════════════════════════════════════
 
HASH      2d437acfbb64
DATE      2024-12-01
SUBJECT   ookflix: initial ookflix commit
FILES     12 CHANGED
HASH      2d437acfbb64
DATE      2024-12-01
SUBJECT   ookflix: initial ookflix commit
FILES     12 CHANGED
 

diff --git a/modules/nixos/server/options.nix b/modules/nixos/server/options.nix
index 4de3252..06e8808 100644
--- a/modules/nixos/server/options.nix
+++ b/modules/nixos/server/options.nix
@@ -14,7 +14,7 @@ in {
       description = "The server profile the host will use as a base";
     };
     services = mkOption {
-      type = listOf (enum ["media-server" "website" "forgejo"]);
+      type = listOf (enum ["media-server" "website" "forgejo" "ookflix"]);
       default = [];
       description = "List of services the server will host";
     };

diff --git a/modules/nixos/server/options.ni
x b/modules/nixos/server/options.nix
index 4de3252..06e8808 100644
--- a/modules/nixos/server/options.nix
+++ b/modules/nixos/server/options.nix
@@ -14,7 +14,7 @@ in {
       description = "The server profile the
 host will use as a base";
     };
     services = mkOption {
-      type = listOf (enum ["media-server" "
website" "forgejo"]);
+      type = listOf (enum ["media-server" "
website" "forgejo" "ookflix"]);
       default = [];
       description = "List of services the s
erver will host";
     };
 

diff --git a/modules/nixos/server/services/default.nix b/modules/nixos/server/serv
ices/default.nix
index 7685461..468b980 100644
--- a/modules/nixos/server/services/default.nix
+++ b/modules/nixos/server/services/default.nix
@@ -3,5 +3,6 @@
     ./website
     ./forgejo
     ./media-server
+    ./ookflix
   ];
 }

diff --git a/modules/nixos/server/services/d
efault.nix b/modules/nixos/server/services/d
efault.nix
index 7685461..468b980 100644
--- a/modules/nixos/server/services/default.
nix
+++ b/modules/nixos/server/services/default.
nix
@@ -3,5 +3,6 @@
     ./website
     ./forgejo
     ./media-server
+    ./ookflix
   ];
 }
 

diff --git a/modules/nixos/server/services/ookflix/default.nix b/modules/nixos/ser
ver/services/ookflix/default.nix
new file mode 100644
index 0000000..8b99d22
--- /dev/null
+++ b/modules/nixos/server/services/ookflix/default.nix
@@ -0,0 +1,24 @@
+{
+  lib,
+  config,
+  ...
+}: let
+  inherit (lib) elem mkIf;
+  inherit (config.ooknet.server) services;
+in {
+  imports = [
+    ./jellyfin.nix
+    ./plex.nix
+    ./options.nix
+  ];
+
+  config = mkIf (elem "ookflix" services) {
+    ooknet.server.ookflix = {
+      gpuAcceleration.enable = true;
+      services = {
+        jellyfin.enable = true;
+        plex.enable = true;
+      };
+    };
+  };
+}

diff --git a/modules/nixos/server/services/o
okflix/default.nix b/modules/nixos/server/se
rvices/ookflix/default.nix
new file mode 100644
index 0000000..8b99d22
--- /dev/null
+++ b/modules/nixos/server/services/ookflix/
default.nix
@@ -0,0 +1,24 @@
+{
+  lib,
+  config,
+  ...
+}: let
+  inherit (lib) elem mkIf;
+  inherit (config.ooknet.server) services;
+in {
+  imports = [
+    ./jellyfin.nix
+    ./plex.nix
+    ./options.nix
+  ];
+
+  config = mkIf (elem "ookflix" services) {
+    ooknet.server.ookflix = {
+      gpuAcceleration.enable = true;
+      services = {
+        jellyfin.enable = true;
+        plex.enable = true;
+      };
+    };
+  };
+}
 

diff --git a/modules/nixos/server/services/ookflix/jellyfin.nix b/modules/nixos/se
rver/services/ookflix/jellyfin.nix
new file mode 100644
index 0000000..cf6738f
--- /dev/null
+++ b/modules/nixos/server/services/ookflix/jellyfin.nix
@@ -0,0 +1,60 @@
+{
+  config,
+  lib,
+  ook,
+  ...
+}: let
+  ookflixLib = import ./lib.nix {inherit lib config;};
+  inherit (ookflixLib) mkServiceStateDir mkServiceUser;
+  inherit (lib) mkIf optionalAttrs;
+  inherit (ook.lib.container) mkContainerLabel mkContainerEnvironment mkContainer
Port;
+  inherit (config.ooknet.server.ookflix) volumes services groups gpuAcceleration;
+  inherit (config.ooknet.server.ookflix.services) jellyfin;
+in {
+  config = mkIf services.jellyfin.enable {
+    hardware.nvidia-container-toolkit.enable = gpuAcceleration.enable && gpuAccel
eration.type == "nvidia";
+    users = mkServiceUser jellyfin.user.name;
+    systemd.tmpfiles = mkServiceStateDir "jellyfin" jellyfin.stateDir;
+    virtualisation.oci-containers.containers = {
+      # media streaming server
+      # docs: <https://docs.linuxserver.io/images/docker-jellyfin/>
+      jellyfin = {
+        image = "lscr.io/linuxserver/jellyfin:latest";
+        autoStart = true;
+        hostname = "jellyfin";
+        ports = [(mkContainerPort jellyfin.port)];
+        volumes = [
+          "${volumes.media.movies}:/data/movies"
+          "${volumes.media.tv}:/data/tv"
+          "${jellyfin.stateDir}:/config"
+        ];
+        labels = mkContainerLabel {
+          name = "jellyfin";
+          inherit (jellyfin) port domain;
+          homepage = {
+            group = "media";
+            description = "media-server streamer";
+          };
+        };
+
+        extraOptions = optionalAttrs gpuAcceleration.enable (
+          if gpuAcceleration.type == "nvidia"
+          then [
+            "--runtime=nvidia"
+          ]
+          else if gpuAcceleration.type == "intel" || "amd"
+          then [
+            "--device=/dev/dri:/dev/dri"
+          ]
+          else []
+        );
+        environment =
+          mkContainerEnvironment jellyfin.user.id groups.media.id
+          // {JELLYFIN_PublishedServerUrl = jellyfin.domain;}
+          // optionalAttrs (gpuAcceleration.enable && gpuAcceleration.type == "nv
idia") {
+            NVIDIA_VISIBLE_DEVICES = "all";
+          };
+      };
+    };
+  };
+}

diff --git a/modules/nixos/server/services/o
okflix/jellyfin.nix b/modules/nixos/server/s
ervices/ookflix/jellyfin.nix
new file mode 100644
index 0000000..cf6738f
--- /dev/null
+++ b/modules/nixos/server/services/ookflix/
jellyfin.nix
@@ -0,0 +1,60 @@
+{
+  config,
+  lib,
+  ook,
+  ...
+}: let
+  ookflixLib = import ./lib.nix {inherit li
b config;};
+  inherit (ookflixLib) mkServiceStateDir mk
ServiceUser;
+  inherit (lib) mkIf optionalAttrs;
+  inherit (ook.lib.container) mkContainerLa
bel mkContainerEnvironment mkContainerPort;
+  inherit (config.ooknet.server.ookflix) vo
lumes services groups gpuAcceleration;
+  inherit (config.ooknet.server.ookflix.ser
vices) jellyfin;
+in {
+  config = mkIf services.jellyfin.enable {
+    hardware.nvidia-container-toolkit.enabl
e = gpuAcceleration.enable && gpuAcceleratio
n.type == "nvidia";
+    users = mkServiceUser jellyfin.user.nam
e;
+    systemd.tmpfiles = mkServiceStateDir "j
ellyfin" jellyfin.stateDir;
+    virtualisation.oci-containers.container
s = {
+      # media streaming server
+      # docs: <https://docs.linuxserver.io/
images/docker-jellyfin/>
+      jellyfin = {
+        image = "lscr.io/linuxserver/jellyf
in:latest";
+        autoStart = true;
+        hostname = "jellyfin";
+        ports = [(mkContainerPort jellyfin.
port)];
+        volumes = [
+          "${volumes.media.movies}:/data/mo
vies"
+          "${volumes.media.tv}:/data/tv"
+          "${jellyfin.stateDir}:/config"
+        ];
+        labels = mkContainerLabel {
+          name = "jellyfin";
+          inherit (jellyfin) port domain;
+          homepage = {
+            group = "media";
+            description = "media-server str
eamer";
+          };
+        };
+
+        extraOptions = optionalAttrs gpuAcc
eleration.enable (
+          if gpuAcceleration.type == "nvidi
a"
+          then [
+            "--runtime=nvidia"
+          ]
+          else if gpuAcceleration.type == "
intel" || "amd"
+          then [
+            "--device=/dev/dri:/dev/dri"
+          ]
+          else []
+        );
+        environment =
+          mkContainerEnvironment jellyfin.u
ser.id groups.media.id
+          // {JELLYFIN_PublishedServerUrl =
 jellyfin.domain;}
+          // optionalAttrs (gpuAcceleration
.enable && gpuAcceleration.type == "nvidia")
 {
+            NVIDIA_VISIBLE_DEVICES = "all";
+          };
+      };
+    };
+  };
+}
 

diff --git a/modules/nixos/server/services/ookflix/jellyseer.nix b/modules/nixos/s
erver/services/ookflix/jellyseer.nix
new file mode 100644
index 0000000..382c63d
--- /dev/null
+++ b/modules/nixos/server/services/ookflix/jellyseer.nix
@@ -0,0 +1,32 @@
+{
+  config,
+  lib,
+  ook,
+  ...
+}: let
+  inherit (lib) mkIf;
+  inherit (ook.lib.container) mkContainerLabel mkContainerEnvironment mkContainer
Port;
+  inherit (config.ooknet.server.ookflix) storage groups;
+  inherit (config.ooknet.server.ookflix.services) jellyseer;
+in {
+  config = mkIf jellyseer.enable {
+    # media requesting for jellyfin
+    jellyseer = {
+      image = "fallenbagel/jellyseerr:latest";
+      autoStart = true;
+      hostname = "jellyseer";
+      ports = [(mkContainerPort jellyseer.port)];
+      volumes = ["${storage.state.jellyseer}:/config"];
+      extraOptions = ["--network" "host"];
+      labels = mkContainerLabel {
+        name = "jellyseer";
+        inherit (jellyseer) domain port;
+        homepage = {
+          group = "media";
+          description = "media-server requesting";
+        };
+      };
+      environment = mkContainerEnvironment jellyseer.user.id groups.media.id;
+    };
+  };
+}

diff --git a/modules/nixos/server/services/o
okflix/jellyseer.nix b/modules/nixos/server/
services/ookflix/jellyseer.nix
new file mode 100644
index 0000000..382c63d
--- /dev/null
+++ b/modules/nixos/server/services/ookflix/
jellyseer.nix
@@ -0,0 +1,32 @@
+{
+  config,
+  lib,
+  ook,
+  ...
+}: let
+  inherit (lib) mkIf;
+  inherit (ook.lib.container) mkContainerLa
bel mkContainerEnvironment mkContainerPort;
+  inherit (config.ooknet.server.ookflix) st
orage groups;
+  inherit (config.ooknet.server.ookflix.ser
vices) jellyseer;
+in {
+  config = mkIf jellyseer.enable {
+    # media requesting for jellyfin
+    jellyseer = {
+      image = "fallenbagel/jellyseerr:lates
t";
+      autoStart = true;
+      hostname = "jellyseer";
+      ports = [(mkContainerPort jellyseer.p
ort)];
+      volumes = ["${storage.state.jellyseer
}:/config"];
+      extraOptions = ["--network" "host"];
+      labels = mkContainerLabel {
+        name = "jellyseer";
+        inherit (jellyseer) domain port;
+        homepage = {
+          group = "media";
+          description = "media-server reque
sting";
+        };
+      };
+      environment = mkContainerEnvironment 
jellyseer.user.id groups.media.id;
+    };
+  };
+}
 

diff --git a/modules/nixos/server/services/ookflix/lib.nix b/modules/nixos/server/
services/ookflix/lib.nix
new file mode 100644
index 0000000..ba25024
--- /dev/null
+++ b/modules/nixos/server/services/ookflix/lib.nix
@@ -0,0 +1,111 @@
+{
+  lib,
+  config,
+  ...
+}: let
+  inherit (lib) mkOption mkEnableOption elem assertMsg;
+  inherit (builtins) attrValues;
+  inherit (lib.types) int path port str;
+  inherit (config.ooknet) server;
+  cfg = server.ookflix;
+
+  mkSubdomainOption = name: description: example:
+    mkOption {
+      type = str;
+      default = "${name}.${server.domain}";
+      inherit description example;
+    };
+
+  # check config.ids for static uid/gid based on service name, if available use t
hat, if not, use fallback.
+  # check fallback doesnt conflict with existing static id
+  getId = idType: name: fallback: let
+    allNixosIds = attrValues config.ids.${idType};
+    fallbackConflict = elem fallback allNixosIds;
+  in
+    mkOption {
+      type = int;
+      default =
+        config.ids.${idType}.${name}
+        or (
+          assert assertMsg (!fallbackConflict)
+          "Fallback ${idType} ${toString fallback} for ${name} conflicts with Nix
OS static allocation"; fallback
+        );
+      description = "${idType} of ${name} container";
+      example = 224;
+    };
+
+  mkUserOption = name: fallback: {
+    name = mkOption {
+      type = str;
+      default = name;
+      description = "Name of ${name} container user";
+      example = "${name}";
+    };
+    id = getId "uids" name fallback;
+  };
+
+  mkGroupOption = name: fallback: {
+    name = mkOption {
+      type = str;
+      default = name;
+    };
+    id = getId "gids" name fallback;
+  };
+
+  mkPortOption = value: description: example:
+    mkOption {
+      type = port;
+      default = value;
+      inherit description example;
+    };
+
+  mkVolumeOption = type: pathValue:
+    mkOption {
+      type = path;
+      default =
+        if type == "state"
+        then "${cfg.volumes.state.root}/${pathValue}"
+        else if type == "media"
+        then "${cfg.volumes.media.root}/${pathValue}"
+        else if type == "downloads"
+        then "${cfg.volumes.downloads.root}/${pathValue}"
+        else if type == "root"
+        then pathValue
+        else throw "Invalid VolumeOption type: ${type}. Must be one of 'state' 'm
edia' 'downloads' 'root'";
+    };
+
+  mkServiceOptions = name: {
+    port,
+    gid,
+    uid,
+    ...
+  } @ args: {
+    enable = mkEnableOption "Enable ${name} container";
+    port = mkPortOption args.port "Port for ${name} container." 80;
+    domain = mkSubdomainOption name "Domain for ${name} container." "${name}.mydo
main.com";
+    stateDir = mkVolumeOption "state" name;
+    user = mkUserOption name args.uid;
+    group = mkGroupOption name args.gid;
+  };
+  mkServiceUser = service: {
+    users.${service} = {
+      isSystemUser = true;
+      uid = cfg.services.${service}.user.id;
+      name = service;
+      group = service;
+    };
+    groups.${service} = {
+      gid = cfg.services.${service}.group.id;
+      name = service;
+    };
+  };
+  mkServiceStateDir = service: dir: {
+    settings."${service}StateDir".${dir}."d" = {
+      mode = "0700";
+      user = cfg.services.${service}.user.name;
+      group = cfg.services.${service}.group.name;
+    };
+  };
+in {
+  inherit mkServiceOptions mkServiceStateDir mkServiceUser mkUserOption mkPortOpt
ion mkGroupOption mkVolumeOption mkSubdomainOption;
+}

diff --git a/modules/nixos/server/services/o
okflix/lib.nix b/modules/nixos/server/servic
es/ookflix/lib.nix
new file mode 100644
index 0000000..ba25024
--- /dev/null
+++ b/modules/nixos/server/services/ookflix/
lib.nix
@@ -0,0 +1,111 @@
+{
+  lib,
+  config,
+  ...
+}: let
+  inherit (lib) mkOption mkEnableOption ele
m assertMsg;
+  inherit (builtins) attrValues;
+  inherit (lib.types) int path port str;
+  inherit (config.ooknet) server;
+  cfg = server.ookflix;
+
+  mkSubdomainOption = name: description: ex
ample:
+    mkOption {
+      type = str;
+      default = "${name}.${server.domain}";
+      inherit description example;
+    };
+
+  # check config.ids for static uid/gid bas
ed on service name, if available use that, i
f not, use fallback.
+  # check fallback doesnt conflict with exi
sting static id
+  getId = idType: name: fallback: let
+    allNixosIds = attrValues config.ids.${i
dType};
+    fallbackConflict = elem fallback allNix
osIds;
+  in
+    mkOption {
+      type = int;
+      default =
+        config.ids.${idType}.${name}
+        or (
+          assert assertMsg (!fallbackConfli
ct)
+          "Fallback ${idType} ${toString fa
llback} for ${name} conflicts with NixOS sta
tic allocation"; fallback
+        );
+      description = "${idType} of ${name} c
ontainer";
+      example = 224;
+    };
+
+  mkUserOption = name: fallback: {
+    name = mkOption {
+      type = str;
+      default = name;
+      description = "Name of ${name} contai
ner user";
+      example = "${name}";
+    };
+    id = getId "uids" name fallback;
+  };
+
+  mkGroupOption = name: fallback: {
+    name = mkOption {
+      type = str;
+      default = name;
+    };
+    id = getId "gids" name fallback;
+  };
+
+  mkPortOption = value: description: exampl
e:
+    mkOption {
+      type = port;
+      default = value;
+      inherit description example;
+    };
+
+  mkVolumeOption = type: pathValue:
+    mkOption {
+      type = path;
+      default =
+        if type == "state"
+        then "${cfg.volumes.state.root}/${p
athValue}"
+        else if type == "media"
+        then "${cfg.volumes.media.root}/${p
athValue}"
+        else if type == "downloads"
+        then "${cfg.volumes.downloads.root}
/${pathValue}"
+        else if type == "root"
+        then pathValue
+        else throw "Invalid VolumeOption ty
pe: ${type}. Must be one of 'state' 'media' 
'downloads' 'root'";
+    };
+
+  mkServiceOptions = name: {
+    port,
+    gid,
+    uid,
+    ...
+  } @ args: {
+    enable = mkEnableOption "Enable ${name}
 container";
+    port = mkPortOption args.port "Port for
 ${name} container." 80;
+    domain = mkSubdomainOption name "Domain
 for ${name} container." "${name}.mydomain.c
om";
+    stateDir = mkVolumeOption "state" name;
+    user = mkUserOption name args.uid;
+    group = mkGroupOption name args.gid;
+  };
+  mkServiceUser = service: {
+    users.${service} = {
+      isSystemUser = true;
+      uid = cfg.services.${service}.user.id
;
+      name = service;
+      group = service;
+    };
+    groups.${service} = {
+      gid = cfg.services.${service}.group.i
d;
+      name = service;
+    };
+  };
+  mkServiceStateDir = service: dir: {
+    settings."${service}StateDir".${dir}."d
" = {
+      mode = "0700";
+      user = cfg.services.${service}.user.n
ame;
+      group = cfg.services.${service}.group
.name;
+    };
+  };
+in {
+  inherit mkServiceOptions mkServiceStateDi
r mkServiceUser mkUserOption mkPortOption mk
GroupOption mkVolumeOption mkSubdomainOption
;
+}
 

diff --git a/modules/nixos/server/services/ookflix/options.nix b/modules/nixos/ser
ver/services/ookflix/options.nix
new file mode 100644
index 0000000..7cd5550
--- /dev/null
+++ b/modules/nixos/server/services/ookflix/options.nix
@@ -0,0 +1,92 @@
+{
+  lib,
+  config,
+  ...
+}: let
+  ookflixLib = import ./lib.nix {inherit lib config;};
+
+  inherit (ookflixLib) mkVolumeOption mkGroupOption mkServiceOptions;
+  inherit (lib) mkOption mkEnableOption;
+  inherit (lib.types) enum;
+  inherit (config.ooknet) server;
+  cfg = server.ookflix;
+in {
+  options.ooknet.server.ookflix = {
+    enable = mkEnableOption "Enable ookflix a container based media server module
";
+    gpuAcceleration = {
+      enable = mkEnableOption "Enable GPU acceleration for video streamers";
+      type = mkOption {
+        type = enum ["nvidia" "intel" "amd"];
+        default = config.ooknet.hardware.gpu.type;
+        description = ''
+          What GPU type to use for GPU acceleration.
+          Defaults to system GPU type (ooknet.hardware.gpu.type)
+        '';
+      };
+    };
+    volumes = {
+      state.root = mkVolumeOption "root" "/var/lib/ookflix";
+      content.root = mkVolumeOption "root" "/jellyfin";
+      downloads = {
+        root = mkVolumeOption "${cfg.content.root}/downloads";
+        incomplete = mkVolumeOption "downloads" "incomplete";
+        complete = mkVolumeOption "downloads" "complete";
+        watch = mkVolumeOption "downloads" "watch";
+      };
+
+      media = {
+        root = mkVolumeOption "root" "${cfg.volumes.content.root}/media";
+        movies = mkVolumeOption "media" "movies";
+        tv = mkVolumeOption "media" "tv";
+      };
+    };
+    # Shared groups
+    groups = {
+      media = mkGroupOption "media" 992;
+      downloader = mkGroupOption "downloader" 981;
+    };
+
+    services = {
+      jellyfin = mkServiceOptions "jellyfin" {
+        port = 8096;
+        uid = 994;
+        gid = 994;
+      };
+      plex = mkServiceOptions "plex" {
+        port = 32400;
+        uid = 195;
+        gid = 195;
+      };
+      sonarr = mkServiceOptions "sonarr" {
+        port = 8989;
+        uid = 274;
+        gid = 274;
+      };
+      radarr = mkServiceOptions "radarr" {
+        port = 7878;
+        uid = 275;
+        gid = 275;
+      };
+      prowlarr = mkServiceOptions "prowlarr" {
+        port = 9696;
+        uid = 982;
+        gid = 987;
+      };
+      transmission = mkServiceOptions "transmission" {
+        port = 9091;
+        uid = 70;
+        gid = 70;
+      };
+      jellyseer = mkServiceOptions "jellyseer" {
+        port = 5055;
+        uid = 345;
+        gid = 345;
+      };
+      tautulli = mkServiceOptions "tautulli" {
+        port = 8181;
+        uid = 355;
+        gid = 355;
+      };
+    };
+  };
+}

diff --git a/modules/nixos/server/services/o
okflix/options.nix b/modules/nixos/server/se
rvices/ookflix/options.nix
new file mode 100644
index 0000000..7cd5550
--- /dev/null
+++ b/modules/nixos/server/services/ookflix/
options.nix
@@ -0,0 +1,92 @@
+{
+  lib,
+  config,
+  ...
+}: let
+  ookflixLib = import ./lib.nix {inherit li
b config;};
+
+  inherit (ookflixLib) mkVolumeOption mkGro
upOption mkServiceOptions;
+  inherit (lib) mkOption mkEnableOption;
+  inherit (lib.types) enum;
+  inherit (config.ooknet) server;
+  cfg = server.ookflix;
+in {
+  options.ooknet.server.ookflix = {
+    enable = mkEnableOption "Enable ookflix
 a container based media server module";
+    gpuAcceleration = {
+      enable = mkEnableOption "Enable GPU a
cceleration for video streamers";
+      type = mkOption {
+        type = enum ["nvidia" "intel" "amd"
];
+        default = config.ooknet.hardware.gp
u.type;
+        description = ''
+          What GPU type to use for GPU acce
leration.
+          Defaults to system GPU type (ookn
et.hardware.gpu.type)
+        '';
+      };
+    };
+    volumes = {
+      state.root = mkVolumeOption "root" "/
var/lib/ookflix";
+      content.root = mkVolumeOption "root" 
"/jellyfin";
+      downloads = {
+        root = mkVolumeOption "${cfg.conten
t.root}/downloads";
+        incomplete = mkVolumeOption "downlo
ads" "incomplete";
+        complete = mkVolumeOption "download
s" "complete";
+        watch = mkVolumeOption "downloads" 
"watch";
+      };
+
+      media = {
+        root = mkVolumeOption "root" "${cfg
.volumes.content.root}/media";
+        movies = mkVolumeOption "media" "mo
vies";
+        tv = mkVolumeOption "media" "tv";
+      };
+    };
+    # Shared groups
+    groups = {
+      media = mkGroupOption "media" 992;
+      downloader = mkGroupOption "downloade
r" 981;
+    };
+
+    services = {
+      jellyfin = mkServiceOptions "jellyfin
" {
+        port = 8096;
+        uid = 994;
+        gid = 994;
+      };
+      plex = mkServiceOptions "plex" {
+        port = 32400;
+        uid = 195;
+        gid = 195;
+      };
+      sonarr = mkServiceOptions "sonarr" {
+        port = 8989;
+        uid = 274;
+        gid = 274;
+      };
+      radarr = mkServiceOptions "radarr" {
+        port = 7878;
+        uid = 275;
+        gid = 275;
+      };
+      prowlarr = mkServiceOptions "prowlarr
" {
+        port = 9696;
+        uid = 982;
+        gid = 987;
+      };
+      transmission = mkServiceOptions "tran
smission" {
+        port = 9091;
+        uid = 70;
+        gid = 70;
+      };
+      jellyseer = mkServiceOptions "jellyse
er" {
+        port = 5055;
+        uid = 345;
+        gid = 345;
+      };
+      tautulli = mkServiceOptions "tautulli
" {
+        port = 8181;
+        uid = 355;
+        gid = 355;
+      };
+    };
+  };
+}
 

diff --git a/modules/nixos/server/services/ookflix/plex.nix b/modules/nixos/server
/services/ookflix/plex.nix
new file mode 100644
index 0000000..1bee37e
--- /dev/null
+++ b/modules/nixos/server/services/ookflix/plex.nix
@@ -0,0 +1,66 @@
+{
+  config,
+  lib,
+  ook,
+  ...
+}: let
+  ookflixLib = import ./lib.nix {inherit lib config;};
+  inherit (ookflixLib) mkServiceUser mkServiceStateDir;
+  inherit (lib) mkIf optionalAttrs;
+  inherit (ook.lib.container) mkContainerLabel mkContainerEnvironment mkContainer
Port;
+  inherit (config.ooknet.server.ookflix) gpuAcceleration services volumes groups;
+  inherit (config.ooknet.server.ookflix.services) plex;
+in {
+  config = mkIf plex.enable {
+    # not sure if this is needed for podman
+    hardware.nvidia-container-toolkit.enable = gpuAcceleration.enable && gpuAccel
eration.type == "nvidia";
+
+    # users/group/directories configuration, see lib.nix
+    users = mkServiceUser plex.user.name;
+    systemd.tmpfiles = mkServiceStateDir "plex" plex.stateDir;
+
+    # container configuration
+    virtualisation.oci-containers.containers = {
+      # media streaming server
+      plex = {
+        image = "lscr.io/linuxserver/plex:latest";
+        autoStart = true;
+        hostname = "plex";
+        ports = [(mkContainerPort plex.port)];
+        volumes = [
+          "${volumes.media.movies}:/data/movies"
+          "${volumes.media.tv}:/data/tv"
+          "${plex.stateDir}:/config"
+        ];
+        labels = mkContainerLabel {
+          name = "plex";
+          inherit (plex) domain port;
+          homepage = {
+            group = "media";
+            description = "media-server streamer";
+          };
+        };
+        extraOptions = optionalAttrs gpuAcceleration.enable (
+          if gpuAcceleration.type == "nvidia"
+          then [
+            "--runtime=nvidia"
+          ]
+          else if gpuAcceleration.type == "intel"
+          then [
+            "--device=/dev/dri:/dev/dri"
+          ]
+          else if gpuAcceleration.type == "amd"
+          then [
+            "--device=/dev/dri:/dev/dri"
+          ]
+          else []
+        );
+        environment =
+          mkContainerEnvironment plex.user.id groups.media.id
+          // optionalAttrs (gpuAcceleration.enable && gpuAcceleration.type == "nv
idia") {
+            NVIDIA_VISIBLE_DEVICES = "all";
+          };
+      };
+    };
+  };
+}

diff --git a/modules/nixos/server/services/o
okflix/plex.nix b/modules/nixos/server/servi
ces/ookflix/plex.nix
new file mode 100644
index 0000000..1bee37e
--- /dev/null
+++ b/modules/nixos/server/services/ookflix/
plex.nix
@@ -0,0 +1,66 @@
+{
+  config,
+  lib,
+  ook,
+  ...
+}: let
+  ookflixLib = import ./lib.nix {inherit li
b config;};
+  inherit (ookflixLib) mkServiceUser mkServ
iceStateDir;
+  inherit (lib) mkIf optionalAttrs;
+  inherit (ook.lib.container) mkContainerLa
bel mkContainerEnvironment mkContainerPort;
+  inherit (config.ooknet.server.ookflix) gp
uAcceleration services volumes groups;
+  inherit (config.ooknet.server.ookflix.ser
vices) plex;
+in {
+  config = mkIf plex.enable {
+    # not sure if this is needed for podman
+    hardware.nvidia-container-toolkit.enabl
e = gpuAcceleration.enable && gpuAcceleratio
n.type == "nvidia";
+
+    # users/group/directories configuration
, see lib.nix
+    users = mkServiceUser plex.user.name;
+    systemd.tmpfiles = mkServiceStateDir "p
lex" plex.stateDir;
+
+    # container configuration
+    virtualisation.oci-containers.container
s = {
+      # media streaming server
+      plex = {
+        image = "lscr.io/linuxserver/plex:l
atest";
+        autoStart = true;
+        hostname = "plex";
+        ports = [(mkContainerPort plex.port
)];
+        volumes = [
+          "${volumes.media.movies}:/data/mo
vies"
+          "${volumes.media.tv}:/data/tv"
+          "${plex.stateDir}:/config"
+        ];
+        labels = mkContainerLabel {
+          name = "plex";
+          inherit (plex) domain port;
+          homepage = {
+            group = "media";
+            description = "media-server str
eamer";
+          };
+        };
+        extraOptions = optionalAttrs gpuAcc
eleration.enable (
+          if gpuAcceleration.type == "nvidi
a"
+          then [
+            "--runtime=nvidia"
+          ]
+          else if gpuAcceleration.type == "
intel"
+          then [
+            "--device=/dev/dri:/dev/dri"
+          ]
+          else if gpuAcceleration.type == "
amd"
+          then [
+            "--device=/dev/dri:/dev/dri"
+          ]
+          else []
+        );
+        environment =
+          mkContainerEnvironment plex.user.
id groups.media.id
+          // optionalAttrs (gpuAcceleration
.enable && gpuAcceleration.type == "nvidia")
 {
+            NVIDIA_VISIBLE_DEVICES = "all";
+          };
+      };
+    };
+  };
+}
 

diff --git a/modules/nixos/server/services/ookflix/tautulli.nix b/modules/nixos/se
rver/services/ookflix/tautulli.nix
new file mode 100644
index 0000000..f99fad6
--- /dev/null
+++ b/modules/nixos/server/services/ookflix/tautulli.nix
@@ -0,0 +1,37 @@
+{
+  config,
+  lib,
+  ook,
+  ...
+}: let
+  ookflixLib = import ./lib.nix {inherit lib config;};
+  inherit (ookflixLib) mkServiceUser mkServiceStateDir;
+  inherit (lib) mkIf;
+  inherit (ook.lib.container) mkContainerLabel mkContainerEnvironment mkContainer
Port;
+  inherit (config.ooknet.server.ookflix) groups;
+  inherit (config.ooknet.server.services) tautulli;
+in {
+  config = mkIf tautulli.enable {
+    users = mkServiceUser tautulli.user.name;
+    systemd.tmpfiles = mkServiceStateDir "tautulli" tautulli.stateDir;
+    virtualisation.oci-containers.containers = {
+      # plex monitoring service
+      tautulli = {
+        image = "lscr.io/linuxserver/tautulli:latest";
+        autoStart = true;
+        hostname = "tautulli";
+        ports = [(mkContainerPort tautulli.port)];
+        volumes = ["${tautulli.stateDir}:/config"];
+        labels = mkContainerLabel {
+          name = "tautulli";
+          inherit (tautulli) port domain;
+          homepage = {
+            group = "monitoring";
+            description = "media-server monitoring";
+          };
+        };
+        environment = mkContainerEnvironment tautulli.user.id groups.media.id;
+      };
+    };
+  };
+}

diff --git a/modules/nixos/server/services/o
okflix/tautulli.nix b/modules/nixos/server/s
ervices/ookflix/tautulli.nix
new file mode 100644
index 0000000..f99fad6
--- /dev/null
+++ b/modules/nixos/server/services/ookflix/
tautulli.nix
@@ -0,0 +1,37 @@
+{
+  config,
+  lib,
+  ook,
+  ...
+}: let
+  ookflixLib = import ./lib.nix {inherit li
b config;};
+  inherit (ookflixLib) mkServiceUser mkServ
iceStateDir;
+  inherit (lib) mkIf;
+  inherit (ook.lib.container) mkContainerLa
bel mkContainerEnvironment mkContainerPort;
+  inherit (config.ooknet.server.ookflix) gr
oups;
+  inherit (config.ooknet.server.services) t
autulli;
+in {
+  config = mkIf tautulli.enable {
+    users = mkServiceUser tautulli.user.nam
e;
+    systemd.tmpfiles = mkServiceStateDir "t
autulli" tautulli.stateDir;
+    virtualisation.oci-containers.container
s = {
+      # plex monitoring service
+      tautulli = {
+        image = "lscr.io/linuxserver/tautul
li:latest";
+        autoStart = true;
+        hostname = "tautulli";
+        ports = [(mkContainerPort tautulli.
port)];
+        volumes = ["${tautulli.stateDir}:/c
onfig"];
+        labels = mkContainerLabel {
+          name = "tautulli";
+          inherit (tautulli) port domain;
+          homepage = {
+            group = "monitoring";
+            description = "media-server mon
itoring";
+          };
+        };
+        environment = mkContainerEnvironmen
t tautulli.user.id groups.media.id;
+      };
+    };
+  };
+}
 

diff --git a/modules/nixos/server/services/ookflix/users.nix b/modules/nixos/serve
r/services/ookflix/users.nix
new file mode 100644
index 0000000..63790b0
--- /dev/null
+++ b/modules/nixos/server/services/ookflix/users.nix
@@ -0,0 +1,38 @@
+{
+  lib,
+  config,
+  ...
+}: let
+  inherit (lib) mkIf mkMerge;
+  inherit (builtins) mapAttrs;
+  inherit (config.ooknet.server) ookflix;
+  inherit (config.ooknet.server.ookflix) services storage users groups;
+
+  mkServiceUser = name: user: {
+    isSystemUser = true;
+    group = groups.${name}.name;
+    uid = users.${name}.id;
+    home = storage.state.${name};
+  };
+
+  generateUsers = mapAttrs mkServiceUser users;
+in {
+  config = mkIf ookflix.enable {
+    users = {
+      users = mkMerge [
+        # media service users
+        (mkIf services.jellyfin.enable {
+          ${users.jellyfin.name} = mkServiceUser users.jellyfin.name groups.media
.name;
+        })
+        (mkIf services.plex.enable {
+          ${users.plex.name} = mkServiceUser users.plex.name groups.media.name;
+        })
+        (mkIf (services.jellyfin.enable || services.jellyseer.enable) {
+          ${users.jellyseer.name} = mkServiceUser users.jellyseer.name groups.med
ia.name;
+        })
+      ];
+      groups = {
+      };
+    };
+  };
+}

diff --git a/modules/nixos/server/services/o
okflix/users.nix b/modules/nixos/server/serv
ices/ookflix/users.nix
new file mode 100644
index 0000000..63790b0
--- /dev/null
+++ b/modules/nixos/server/services/ookflix/
users.nix
@@ -0,0 +1,38 @@
+{
+  lib,
+  config,
+  ...
+}: let
+  inherit (lib) mkIf mkMerge;
+  inherit (builtins) mapAttrs;
+  inherit (config.ooknet.server) ookflix;
+  inherit (config.ooknet.server.ookflix) se
rvices storage users groups;
+
+  mkServiceUser = name: user: {
+    isSystemUser = true;
+    group = groups.${name}.name;
+    uid = users.${name}.id;
+    home = storage.state.${name};
+  };
+
+  generateUsers = mapAttrs mkServiceUser us
ers;
+in {
+  config = mkIf ookflix.enable {
+    users = {
+      users = mkMerge [
+        # media service users
+        (mkIf services.jellyfin.enable {
+          ${users.jellyfin.name} = mkServic
eUser users.jellyfin.name groups.media.name;
+        })
+        (mkIf services.plex.enable {
+          ${users.plex.name} = mkServiceUse
r users.plex.name groups.media.name;
+        })
+        (mkIf (services.jellyfin.enable || 
services.jellyseer.enable) {
+          ${users.jellyseer.name} = mkServi
ceUser users.jellyseer.name groups.media.nam
e;
+        })
+      ];
+      groups = {
+      };
+    };
+  };
+}
 

diff --git a/outputs/lib/containers.nix b/outputs/lib/containers.nix
index 829f800..36c002d 100644
--- a/outputs/lib/containers.nix
+++ b/outputs/lib/containers.nix
@@ -1,4 +1,8 @@
-{lib, ...}: let
+{
+  lib,
+  config,
+  ...
+}: let
   inherit (builtins) isBool;
   inherit (lib) toUpper optionalAttrs mapAttrs' nameValuePair;
 
@@ -33,7 +37,7 @@
   in
     commonLabels // (processWidget widget);
 
-  mkContainerLabels = {name, ...} @ args: let
+  mkContainerLabel = {name, ...} @ args: let
     homepage = args.homepage or {};
     baseWidget = homepage.widget or {};
   in
@@ -52,16 +56,25 @@
     # homepage labels
     // (optionalAttrs (args ? homepage) (mkHomepageLabels {
       inherit name;
-      inherit (args) domain;
+      domain = "https://${args.domain}";
       group = args.homepage.group or name;
       widget =
         baseWidget
         // {
           type = name;
-          url = args.domain;
+          url = "https://${args.domain}";
           key = "{{HOMEPAGE_FILE_${toUpper name}}}";
         };
     }));
+
+  mkContainerEnvironment = user: group: {
+    PUID = toString user;
+    PGID = toString group;
+    # TODO: I dont want to hard code this
+    TZ = "Antarctica/Macquarie";
+  };
+
+  mkContainerPort = port: "${toString port}:${toString port}";
 in {
-  inherit mkContainerLabels;
+  inherit mkContainerLabel mkContainerEnvironment mkContainerPort;
 }

diff --git a/outputs/lib/containers.nix b/ou
tputs/lib/containers.nix
index 829f800..36c002d 100644
--- a/outputs/lib/containers.nix
+++ b/outputs/lib/containers.nix
@@ -1,4 +1,8 @@
-{lib, ...}: let
+{
+  lib,
+  config,
+  ...
+}: let
   inherit (builtins) isBool;
   inherit (lib) toUpper optionalAttrs mapAt
trs' nameValuePair;
 
@@ -33,7 +37,7 @@
   in
     commonLabels // (processWidget widget);
 
-  mkContainerLabels = {name, ...} @ args: l
et
+  mkContainerLabel = {name, ...} @ args: le
t
     homepage = args.homepage or {};
     baseWidget = homepage.widget or {};
   in
@@ -52,16 +56,25 @@
     # homepage labels
     // (optionalAttrs (args ? homepage) (mk
HomepageLabels {
       inherit name;
-      inherit (args) domain;
+      domain = "https://${args.domain}";
       group = args.homepage.group or name;
       widget =
         baseWidget
         // {
           type = name;
-          url = args.domain;
+          url = "https://${args.domain}";
           key = "{{HOMEPAGE_FILE_${toUpper 
name}}}";
         };
     }));
+
+  mkContainerEnvironment = user: group: {
+    PUID = toString user;
+    PGID = toString group;
+    # TODO: I dont want to hard code this
+    TZ = "Antarctica/Macquarie";
+  };
+
+  mkContainerPort = port: "${toString port}
:${toString port}";
 in {
-  inherit mkContainerLabels;
+  inherit mkContainerLabel mkContainerEnvir
onment mkContainerPort;
 }
 

diff --git a/outputs/lib/default.nix b/outputs/lib/default.nix
index 42ee09f..4492913 100644
--- a/outputs/lib/default.nix
+++ b/outputs/lib/default.nix
@@ -2,6 +2,7 @@
   lib,
   self,
   inputs,
+  config,
   ...
 }: let
   # my scuffed lib
@@ -9,6 +10,7 @@
     builders = import ./builders.nix {inherit self lib inputs;};
     mkNeovim = import ./mkNeovim.nix {inherit inputs;};
     math = import ./math.nix {inherit lib;};
+    container = import ./containers.nix {inherit lib config;};
     color = let
       check = import ./color/check.nix {inherit lib;};
       types = import ./color/types.nix {

diff --git a/outputs/lib/default.nix b/outpu
ts/lib/default.nix
index 42ee09f..4492913 100644
--- a/outputs/lib/default.nix
+++ b/outputs/lib/default.nix
@@ -2,6 +2,7 @@
   lib,
   self,
   inputs,
+  config,
   ...
 }: let
   # my scuffed lib
@@ -9,6 +10,7 @@
     builders = import ./builders.nix {inher
it self lib inputs;};
     mkNeovim = import ./mkNeovim.nix {inher
it inputs;};
     math = import ./math.nix {inherit lib;}
;
+    container = import ./containers.nix {in
herit lib config;};
     color = let
       check = import ./color/check.nix {inh
erit lib;};
       types = import ./color/types.nix {
 
[ BACK TO LOG ]
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET