Unverified Commit 99e3c003 authored by h7x4's avatar h7x4 Committed by GitHub
Browse files

Merge pull request #281871 from RatCornu/tachidesk-server

 nixos/suwayomi-server: init at 0.7.0
parents 2489c434 d32bb111
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -15510,6 +15510,16 @@
    githubId = 1891350;
    name = "Michael Raskin";
  };
  ratcornu = {
    email = "ratcornu@skaven.org";
    github = "RatCornu";
    githubId = 98173832;
    name = "Balthazar Patiachvili";
    matrix = "@ratcornu:skweel.skaven.org";
    keys = [{
      fingerprint = "1B91 F087 3D06 1319 D3D0  7F91 FA47 BDA2 6048 9ADA";
    }];
  };
  ratsclub = {
    email = "victor@freire.dev.br";
    github = "ratsclub";
+2 −0
Original line number Diff line number Diff line
@@ -37,6 +37,8 @@ In addition to numerous new and upgraded packages, this release has the followin
- [Anki Sync Server](https://docs.ankiweb.net/sync-server.html), the official sync server built into recent versions of Anki. Available as [services.anki-sync-server](#opt-services.anki-sync-server.enable).
The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been marked deprecated and will be dropped after 24.05 due to lack of maintenance of the anki-sync-server softwares.

- [Suwayomi Server](https://github.com/Suwayomi/Suwayomi-Server), a free and open source manga reader server that runs extensions built for [Tachiyomi](https://tachiyomi.org). Available as [services.suwayomi-server](#opt-services.suwayomi-server.enable).

- [ping_exporter](https://github.com/czerwonk/ping_exporter), a Prometheus exporter for ICMP echo requests. Available as [services.prometheus.exporters.ping](#opt-services.prometheus.exporters.ping.enable).

- [Clevis](https://github.com/latchset/clevis), a pluggable framework for automated decryption, used to unlock encrypted devices in initrd. Available as [boot.initrd.clevis.enable](#opt-boot.initrd.clevis.enable).
+1 −0
Original line number Diff line number Diff line
@@ -1339,6 +1339,7 @@
  ./services/web-apps/restya-board.nix
  ./services/web-apps/rimgo.nix
  ./services/web-apps/sftpgo.nix
  ./services/web-apps/suwayomi-server.nix
  ./services/web-apps/rss-bridge.nix
  ./services/web-apps/selfoss.nix
  ./services/web-apps/shiori.nix
+108 −0
Original line number Diff line number Diff line
# Suwayomi-Server {#module-services-suwayomi-server}

A free and open source manga reader server that runs extensions built for Tachiyomi.

## Basic usage {#module-services-suwayomi-server-basic-usage}

By default, the module will execute Suwayomi-Server backend and web UI:

```nix
{ ... }:

{
  services.suwayomi-server = {
    enable = true;
  };
}
```

It runs in the systemd service named `suwayomi-server` in the data directory `/var/lib/suwayomi-server`.

You can change the default parameters with some other parameters:
```nix
{ ... }:

{
  services.suwayomi-server = {
    enable = true;

    dataDir = "/var/lib/suwayomi"; # Default is "/var/lib/suwayomi-server"
    openFirewall = true;

    settings = {
      server.port = 4567;
    };
  };
}
```

If you want to create a desktop icon, you can activate the system tray option:

```nix
{ ... }:

{
  services.suwayomi-server = {
    enable = true;

    dataDir = "/var/lib/suwayomi"; # Default is "/var/lib/suwayomi-server"
    openFirewall = true;

    settings = {
      server.port = 4567;
      server.enableSystemTray = true;
    };
  };
}
```

## Basic authentication {#module-services-suwayomi-server-basic-auth}

You can configure a basic authentication to the web interface with:

```nix
{ ... }:

{
  services.suwayomi-server = {
    enable = true;

    openFirewall = true;

    settings = {
      server.port = 4567;
      server = {
        basicAuthEnabled = true;
        basicAuthUsername = "username";

        # NOTE: this is not a real upstream option
        basicAuthPasswordFile = ./path/to/the/password/file;
      };
    };
  };
}
```

## Extra configuration {#module-services-suwayomi-server-extra-config}

Not all the configuration options are available directly in this module, but you can add the other options of suwayomi-server with:

```nix
{ ... }:

{
  services.suwayomi-server = {
    enable = true;

    openFirewall = true;

    settings = {
      server = {
        port = 4567;
        autoDownloadNewChapters = false;
        maxSourcesInParallel" = 6;
      };
    };
  };
}
```
+260 −0
Original line number Diff line number Diff line
{ config, pkgs, lib, ... }:

let
  cfg = config.services.suwayomi-server;
  inherit (lib) mkOption mdDoc mkEnableOption mkIf types;
in
{
  options = {
    services.suwayomi-server = {
      enable = mkEnableOption (mdDoc "Suwayomi, a free and open source manga reader server that runs extensions built for Tachiyomi.");

      package = lib.mkPackageOptionMD pkgs "suwayomi-server" { };

      dataDir = mkOption {
        type = types.path;
        default = "/var/lib/suwayomi-server";
        example = "/var/data/mangas";
        description = mdDoc ''
          The path to the data directory in which Suwayomi-Server will download scans.
        '';
      };

      user = mkOption {
        type = types.str;
        default = "suwayomi";
        example = "root";
        description = mdDoc ''
          User account under which Suwayomi-Server runs.
        '';
      };

      group = mkOption {
        type = types.str;
        default = "suwayomi";
        example = "medias";
        description = mdDoc ''
          Group under which Suwayomi-Server runs.
        '';
      };

      openFirewall = mkOption {
        type = types.bool;
        default = false;
        description = mdDoc ''
          Whether to open the firewall for the port in {option}`services.suwayomi-server.settings.server.port`.
        '';
      };

      settings = mkOption {
        type = types.submodule {
          freeformType =
            let
              recursiveAttrsType = with types; attrsOf (nullOr (oneOf [
                str
                path
                int
                float
                bool
                (listOf str)
                (recursiveAttrsType // { description = "instances of this type recursively"; })
              ]));
            in
            recursiveAttrsType;
          options = {
            server = {
              ip = mkOption {
                type = types.str;
                default = "0.0.0.0";
                example = "127.0.0.1";
                description = mdDoc ''
                  The ip that Suwayomi will bind to.
                '';
              };

              port = mkOption {
                type = types.port;
                default = 8080;
                example = 4567;
                description = mdDoc ''
                  The port that Suwayomi will listen to.
                '';
              };

              basicAuthEnabled = mkEnableOption (mdDoc ''
                Add basic access authentication to Suwayomi-Server.
                Enabling this option is useful when hosting on a public network/the Internet
              '');

              basicAuthUsername = mkOption {
                type = types.nullOr types.str;
                default = null;
                description = mdDoc ''
                  The username value that you have to provide when authenticating.
                '';
              };

              # NOTE: this is not a real upstream option
              basicAuthPasswordFile = mkOption {
                type = types.nullOr types.path;
                default = null;
                example = "/var/secrets/suwayomi-server-password";
                description = mdDoc ''
                  The password file containing the value that you have to provide when authenticating.
                '';
              };

              downloadAsCbz = mkOption {
                type = types.bool;
                default = false;
                description = mdDoc ''
                  Download chapters as `.cbz` files.
                '';
              };

              localSourcePath = mkOption {
                type = types.path;
                default = cfg.dataDir;
                defaultText = lib.literalExpression "suwayomi-server.dataDir";
                example = "/var/data/local_mangas";
                description = mdDoc ''
                  Path to the local source folder.
                '';
              };

              systemTrayEnabled = mkOption {
                type = types.bool;
                default = false;
                description = mdDoc ''
                  Whether to enable a system tray icon, if possible.
                '';
              };
            };
          };
        };
        description = mdDoc ''
          Configuration to write to {file}`server.conf`.
          See <https://github.com/Suwayomi/Suwayomi-Server/wiki/Configuring-Suwayomi-Server> for more information.
        '';
        default = { };
        example = {
          server.socksProxyEnabled = true;
          server.socksProxyHost = "yourproxyhost.com";
          server.socksProxyPort = "8080";
        };
      };
    };
  };

  config = mkIf cfg.enable {

    assertions = [{
      assertion = with cfg.settings.server; basicAuthEnabled -> (basicAuthUsername != null && basicAuthPasswordFile != null);
      message = ''
        [suwayomi-server]: the username and the password file cannot be null when the basic auth is enabled
      '';
    }];

    networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.settings.server.port ];

    users.groups = mkIf (cfg.group == "suwayomi") {
      suwayomi = { };
    };

    users.users = mkIf (cfg.user == "suwayomi") {
      suwayomi = {
        group = cfg.group;
        # Need to set the user home because the package writes to ~/.local/Tachidesk
        home = cfg.dataDir;
        description = "Suwayomi Daemon user";
        isSystemUser = true;
      };
    };

    systemd.tmpfiles.settings."10-suwayomi-server" = {
      "${cfg.dataDir}/.local/share/Tachidesk".d = {
        mode = "0700";
        inherit (cfg) user group;
      };
    };

    systemd.services.suwayomi-server =
      let
        flattenConfig = prefix: config:
          lib.foldl'
            lib.mergeAttrs
            { }
            (lib.attrValues
              (lib.mapAttrs
                (k: v:
                  if !(lib.isAttrs v)
                  then { "${prefix}${k}" = v; }
                  else flattenConfig "${prefix}${k}." v
                )
                config
              )
            );

        #  HOCON is a JSON superset that suwayomi-server use for configuration
        toHOCON = attr:
          let
            attrType = builtins.typeOf attr;
          in
          if builtins.elem attrType [ "string" "path" "int" "float" ]
          then ''"${toString attr}"''
          else if attrType == "bool"
          then lib.boolToString attr
          else if attrType == "list"
          then "[\n${lib.concatMapStringsSep ",\n" toHOCON attr}\n]"
          else # attrs, lambda, null
            throw ''
              [suwayomi-server]: invalid config value type '${attrType}'.
            '';

        configFile = pkgs.writeText "server.conf" (lib.pipe cfg.settings [
          (settings: lib.recursiveUpdate settings {
            server.basicAuthPasswordFile = null;
            server.basicAuthPassword =
              if settings.server.basicAuthEnabled
              then "$TACHIDESK_SERVER_BASIC_AUTH_PASSWORD"
              else null;
          })
          (flattenConfig "")
          (lib.filterAttrs (_: x: x != null))
          (lib.mapAttrsToList (name: value: ''${name} = ${toHOCON value}''))
          lib.concatLines
        ]);

      in
      {
        description = "A free and open source manga reader server that runs extensions built for Tachiyomi.";

        wantedBy = [ "multi-user.target" ];
        wants = [ "network-online.target" ];
        after = [ "network-online.target" ];

        script = ''
          ${lib.optionalString cfg.settings.server.basicAuthEnabled ''
            export TACHIDESK_SERVER_BASIC_AUTH_PASSWORD="$(<${cfg.settings.server.basicAuthPasswordFile})"
          ''}
          ${lib.getExe pkgs.envsubst} -i ${configFile} -o ${cfg.dataDir}/.local/share/Tachidesk/server.conf
          ${lib.getExe cfg.package} -Dsuwayomi.tachidesk.config.server.rootDir=${cfg.dataDir}
        '';

        serviceConfig = {
          User = cfg.user;
          Group = cfg.group;

          Type = "simple";
          Restart = "on-failure";

          StateDirectory = mkIf (cfg.dataDir == "/var/lib/suwayomi-server") "suwayomi-server";
        };
      };
  };

  meta = {
    maintainers = with lib.maintainers; [ ratcornu ];
    doc = ./suwayomi-server.md;
  };
}
Loading