Nixflix Documentation

repository·main·Indexed 19 days ago

https://github.com/kiriwalawren/nixflix

A NixOS module for orchestrating a declarative media automation stack (the 'Starr Stack'). It provides a unified configuration interface for services including Sonarr, Radarr, Lidarr, Prowlarr, Jellyfin, Seerr, SABnzbd, and qBittorrent. Key features include API-based configuration, built-in WireGuard VPN support with a kill switch, PostgreSQL backends, reverse proxy integration via nginx or Caddy, and automated service integration for libraries and download clients.

Tokens
7.5K
Snippets
13
Records
21
Agent score
68%

What's inside Nixflix

  1. Overview of Nixflix

    main

    Nixflix is a declarative media server configuration manager designed specifically for NixOS. It automates the configuration of the 'Starr' stack (Sonarr, Radarr, Lidarr, Prowlarr) and Jellyfin by using their official REST APIs. This ensures that your media server settings are version-controlled, idempotent, and follow best practices like TRaSH Guides.

    Key capabilities include:

    • Declarative API Configuration: Settings are applied via NixOS options directly to service APIs.
    • Service Integration: Automatic connective tissue between Seerr, Starr services, Jellyfin, and download clients (SABnzbd, qBittorrent).
    • Infrastructure Support: Built-in WireGuard VPN (with kill switch), PostgreSQL backends, and reverse proxy integration (nginx or Caddy).
    • Unified UI: Support for unified theming via theme.park.
  2. Supported Services in Nixflix

    main

    Nixflix provides specialized management for the following services:

    Starr Stack (Sonarr, Radarr, Lidarr, Prowlarr)

    • API-based configuration.
    • Optional PostgreSQL integration.
    • Reverse proxy support (nginx or Caddy).
    • Automatic directory and root folder management.

    Jellyfin

    • Basic server management.
    • Automatic library configuration based on selected media managers.
    • Plugin and subtitle downloader management.

    Seerr

    • Media request management.
    • Automatic integration with Starr services and Jellyfin libraries.

    Download Clients

    • SABnzbd: Automatic integration with Starr services.
    • qBittorrent: Automatic integration with Starr services.

    Networking & Maintenance

    • WireGuard VPN: Generic support including a kill switch.
    • Maintainerr: Automatic cleanup of old media.
  3. Understand Nixflix automatic service integrations

    main

    Nixflix provides automatic orchestration between enabled services to reduce manual configuration:

    • Jellyfin Libraries: Automatically creates "Shows" (pointing to Sonarr), "Movies" (pointing to Radarr), and "Music" (pointing to Lidarr) libraries based on your mediaDir.
    • Prowlarr Connections: Automatically configures connections to Sonarr, Radarr, and Lidarr.
    • SABnzbd Integration: Automatically configures SABnzbd as a download client for each enabled 'Arr' service, using service-specific categories.
    • SABnzbd Categories: Automatically creates categories in SABnzbd based on enabled services (e.g., radarr, sonarr, sonarr-anime, lidarr, prowlarr).
  4. Understand Maintainerr rule logic and operators

    main

    Maintainerr rules use a section-based logic system to determine how conditions are evaluated.

    Logical Grouping

    • Sections: Rules within the same section are ANDed together. Different sections are ORed together.
    • Operators: Within a section, the first rule must have operator = null. Subsequent rules use:
      • operator = "0": AND the condition.
      • operator = "1": OR the condition.

    Action Values (action)

    The action field corresponds to RulePossibility values:

    ValueNameValueName
    0BIGGER10CONTAINS_PARTIAL
    1SMALLER11NOT_CONTAINS_PARTIAL
    2EQUALS12CONTAINS_ALL
    3NOT_EQUALS13NOT_CONTAINS_ALL
    4CONTAINS14COUNT_EQUALS
    5BEFORE15COUNT_NOT_EQUALS
    6AFTER16COUNT_BIGGER
    7IN_LAST17COUNT_SMALLER
    8IN_NEXT18EXISTS
    9NOT_CONTAINS19NOT_EXISTS

    Servarr Action Values (arrAction)

    Used to define what happens to the media (e.g., deletion or unmonitoring):

    ValueName
    0DELETE
    1UNMONITOR_DELETE_ALL
    2UNMONITOR_DELETE_EXISTING
    3UNMONITOR
    4DO_NOTHING
    5DELETE_SHOW_IF_EMPTY
    6UNMONITOR_SHOW_IF_EMPTY
    7CHANGE_QUALITY_PROFILE
  5. Develop Nixflix locally

    main

    If you are contributing to the Nixflix repository, use the following commands to manage your development environment:

    # Enter development shell
    nix develop
    
    # Format code
    nix fmt
    
    # Check formatting and linting
    nix flake check
  6. Navigate the Nixflix Options Reference

    main

    The Nixflix configuration options are organized into several functional sections. When configuring your deployment, you can find specific settings under the following categories:

    • Core: Top-level Nixflix configuration.
    • Media Management: Settings for request management (Seerr), TV shows (Sonarr/Sonarr Anime), movies (Radarr), music (Lidarr), indexers (Prowlarr), and automated cleanup (Maintainerr).
    • Media Server: Configuration for the Jellyfin streaming server.
    • Download Clients: Settings for Downloadarr, Usenet (SABnzbd), and BitTorrent (qBittorrent).
    • Infrastructure: Low-level service configuration including reverse proxies (Nginx, Caddy), VPN (WireGuard), databases (PostgreSQL), and TRaSH guides automation (Recyclarr).
  7. Configure Jellyfin subtitle acquisition

    main

    To enable subtitle acquisition in Jellyfin using Nixflix, you must configure the nixflix.jellyfin.plugins section and define library-specific subtitleSettings.

    This setup requires secrets for OpenSubtitles credentials managed via sops. You can enable specific plugins like subbuzz, Open Subtitles, and Subtitle Extract to handle different aspects of subtitle fetching and extraction.

    {config, ...}: {
      sops.secrets."opensubtitles-com/api-key" = { };
      sops.secrets."opensubtitles-com/password" = { };
    
      nixflix.jellyfin = {
        enable = true;
    
        plugins = {
          subbuzz = {
            enable = true;
            config = {
              OpenSubUserName = "kiriwalawren";
              OpenSubPassword._secret = config.sops.secrets."opensubtitles-com/password".path;
              OpenSubApiKey._secret = config.sops.secrets."opensubtitles-com/api-key".path;
              EnableOpenSubtitles = true;
              EnableYifySubtitles = true;
              Cache.SubLifeInMinutes = "Always";
            };
          };
    
          "Open Subtitles" = {
            enable = true;
            config = {
              Username = "kiriwalawren";
              Password._secret = config.sops.secrets."opensubtitles-com/password".path;
            };
          };
    
          "Subtitle Extract" = {
            enable = true;
            config.ExtractionDuringLibraryScan = true;
          };
        };
    
        libraries = {
          Shows = { 
            disabledSubtitleFetchers = ["subbuzz"];
            subtitleFetcherOrder = ["subbuzz" "Open Subtitles"];
            subtitleDownloadLanguages = ["eng" "spa"];
            saveSubtitlesWithMedia = true;
            allowEmbeddedSubtitles = "AllowAll";
            requirePerfectSubtitleMatch = true;
            skipSubtitlesIfAudioTrackMatches = false;
            skipSubtitlesIfEmbeddedsubtitlesPresent = true;
          };
          # Repeat for Anime, Movies, etc.
        };
      };
    }
  8. Configure Maintainerr rules via Nix

    main

    Because Maintainerr rules are complex, the recommended workflow is to design them in the Maintainerr UI first, then export the JSON via the API and declare them in your Nix configuration.

    Workflow

    1. Enable Maintainerr: Ensure the service is running.
    2. Design in UI: Open the Maintainerr UI and create rule groups on the Rules page. Configure libraries, data types, collection settings, and rule conditions.
    3. Retrieve JSON: Use the API to get the resulting configuration:
      curl -s http://localhost:6246/api/rules | jq .
    4. Convert to Nix: Convert the JSON to a Nix attribute set and add it to nixflix.maintainerr.rules.
    5. Rebuild: The maintainerr-rules service will sync the state, creating or updating declared groups and deleting those no longer listed.

    Field Mapping & Conversion Notes

    When converting API JSON to Nix, note these specific mapping requirements:

    • library: Use the human-readable title (e.g., "Movies") instead of the libraryId GUID. The service resolves this via GET /api/media-server/libraries.
    • radarrServerName / sonarrServerName: Use the server name as configured in nixflix.maintainerr.settings.radarr or nixflix.maintainerr.settings.sonarr (e.g., "Radarr", "Sonarr Anime"), not the integer ID.
    • arrAction: Map this from collection.arrAction in the API response.
    • listExclusions / forceSeerr: Map these from collection.listExclusions and collection.forceSeerr.
    • rules: The API returns a ruleJson string for each rule. You must parse this string and use its fields directly in your Nix list.

    To easily inspect the parsed rule logic, use this command:

    curl -s http://localhost:6246/api/rules | jq '.[0].rules[].ruleJson | fromjson'
    nixflix.maintainerr.rules = [
      {
        name = "Movies To Delete";
        description = "Deletes movies that have been watched or have been around for too long.";
        library = "Movies";
        dataType = "movie";
        radarrServerName = "Radarr";
        collection = {
          deleteAfterDays = 14;
          overlayEnabled = true;
        };
        rules = [
          {
            customVal = { ruleTypeId = 3; value = "1"; };
            firstVal = [ 6 42 ];
            action = 2;
            section = 0;
          }
        ];
      }
    ];
  9. Add Nixflix to your Nix Flake

    main

    To use Nixflix with Flakes, follow these two steps:

    1. Enable Flakes: Ensure your NixOS configuration has experimental-features set to include flakes and nix-command.
    2. Add as Input: Add nixflix to your inputs in flake.nix. It is recommended to use inputs.nixpkgs.follows = "nixpkgs"; to ensure version consistency.
    3. Include in Modules: Add nixflix.nixosModules.default to your nixosSystem modules list.
    ### Enable Flakes
    ```nix
    {
      nix.settings.experimental-features = ["nix-command" "flakes"];
    }

    Adding Nixflix to Your Flake

    {
      description = "My NixOS Configuration";
    
      inputs = {
        nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    
        nixflix = {
          url = "github:kiriwalawren/nixflix";
          inputs.nixpkgs.follows = "nixpkgs";
        };
      };
    
      outputs = {
        self,
        nixpkgs,
        nixflix,
        ...
      }: {
        nixosConfigurations.yourhost = nixpkgs.lib.nixosSystem {
          system = "x86_64-linux";
          modules = [
            ./configuration.nix
            nixflix.nixosModules.default
          ];
        };
      };
    }
  10. Configure Jellyfin plugins in Nix

    main

    To add a Jellyfin plugin, you must define both the plugin repository (where the manifest is located) and the plugin itself (the package and its configuration).

    1. Define the Repository: Add the manifest URL and its hash to nixflix.jellyfin.system.pluginRepositories.
    2. Define the Plugin: Add the plugin configuration to nixflix.jellyfin.plugins.<name>. You must provide a package using the nixflix.lib.jellyfinPlugins.fromRepo helper, which requires a version and a hash.
    3. Configure Settings: Provide a config attribute set containing the plugin's specific settings.
    let
      fromRepo = nixflix.lib.jellyfinPlugins.fromRepo;
    in {
      nixflix.jellyfin = {
        system.pluginRepositories = {
          "Plugin Name" = {
            url = "https://example.com/manifest.json";
            hash = "sha256-<manifest-hash>";
            enabled = true;
          };
        };
    
        plugins."Plugin Name" = {
          package = fromRepo {
            version = "1.0.0";
            hash = "sha256-<unpacked-plugin-hash>";
          };
          config = {
            # Plugin specific settings go here
            SettingKey = "Value";
          };
        };
      };
    }
  11. How to extract Jellyfin plugin configuration from the UI

    main

    Since plugin settings vary, the recommended workflow to capture exact configuration is:

    1. Configure the manifest in nixflix.jellyfin.system.pluginRepositories and rebuild.
    2. Install the plugin via the Jellyfin UI.
    3. Restart Jellyfin.
    4. Open your browser's Developer Tools (Network tab).
    5. Configure the plugin settings in the Jellyfin UI.
    6. Capture the data from the resulting API call and convert it into a Nix attribute set.
    7. Uninstall the plugin via the UI and restart Jellyfin.
    8. Add the captured attribute set to nixflix.jellyfin.plugins.<name>.config and define the package using fromRepo.
    9. Rebuild.
  12. Configure a basic Nixflix media server setup

    main

    Nixflix uses a Nix configuration pattern to orchestrate a full media stack. A standard setup includes core services (Sonarr, Radarr, Lidarr, Prowlarr), download clients (SABnzbd), media streaming (Jellyfin), and request management (Seerr).

    Key configuration requirements:

    • Secrets Management: Use sops.secrets to provide paths to sensitive data (API keys, passwords, VPN configs). Use the ._secret suffix in service configs to reference these paths.
    • Storage: Define mediaDir for your media files and stateDir for service state.
    • Reverse Proxy: You must choose either nginx or caddy. Do not enable both. Use addHostsEntries = true; if you want Nix to manage DNS entries for your services.
    • VPN: Enable vpn to confine download services to a WireGuard network namespace. Use wgConfFile for the secret path and accessibleFrom to define your local network subnet (e.g., ["192.168.1.0/24"]).
    {
      sops.secrets = {
        "sonarr/api_key" = {};
        # ... other secrets
      };
    
      nixflix = {
        enable = true;
        mediaDir = "/data/media";
        stateDir = "/data/.state";
        mediaUsers = ["myuser" ];
    
        nginx = {
          enable = true;
          addHostsEntries = true;
        };
    
        sonarr = {
          enable = true;
          config = {
            apiKey._secret = config.sops.secrets."sonarr/api_key".path;
            hostConfig.password._secret = config.sops.secrets."sonarr/password".path;
          };
        };
        # ... other services
      };
    }