Unverified Commit 9334ef54 authored by Sandro Jäckel's avatar Sandro Jäckel Committed by GitHub
Browse files

tuliprox: init at 3.1.7 (#453861)

parents ca406bdb aaa5f8f8
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1728,6 +1728,7 @@
  ./services/web-apps/suwayomi-server.nix
  ./services/web-apps/szurubooru.nix
  ./services/web-apps/trilium.nix
  ./services/web-apps/tuliprox.nix
  ./services/web-apps/umami.nix
  ./services/web-apps/vikunja.nix
  ./services/web-apps/wakapi.nix
+336 −0
Original line number Diff line number Diff line
{
  config,
  pkgs,
  lib,
  utils,
  ...
}:
let
  cfg = config.services.tuliprox;
  settingsFormat = pkgs.formats.yaml { };
  systemSettingsYaml = settingsFormat.generate "config.yml" cfg.systemSettings;
  sourceSettingsYaml = settingsFormat.generate "source.yml" cfg.sourceSettings;
  apiProxySettingsYaml = settingsFormat.generate "api-proxy.yml" cfg.apiProxySettings;
  mappingSettingsYaml = settingsFormat.generate "mapping.yml" cfg.mappingSettings;
in
{
  meta.maintainers = with lib.maintainers; [ nyanloutre ];

  options.services.tuliprox = {
    enable = lib.mkEnableOption "Tuliprox IPTV playlist processor & proxy";

    package = lib.mkPackageOption pkgs "tuliprox" { };

    extraArgs = lib.mkOption {
      type = lib.types.listOf lib.types.str;
      default = [ ];
      description = ''
        Additional command-line arguments for the systemd service.

        Refer to the [Tuliprox documentation] for available arguments.

        [Tuliprox documentation]: https://github.com/euzu/tuliprox?tab=readme-ov-file#command-line-arguments
      '';
    };

    systemSettings = lib.mkOption {
      type = settingsFormat.type;
      example = {
        api = {
          host = "0.0.0.0";
          port = 8901;
        };
      };
      description = ''
        Main config file

        Refer to the [Tuliprox documentation] for available attributes

        [Tuliprox documentation]: https://github.com/euzu/tuliprox?tab=readme-ov-file#1-configyml
      '';
    };

    sourceSettings = lib.mkOption {
      type = settingsFormat.type;
      example = {
        templates = [
          {
            name = "not_red_button";
            value = "NOT (Title ~ \"(?i).*red button.*\")";
          }
          {
            name = "not_low_resolution";
            value = "NOT (Title ~ \"(?i).*\(360p|240p\).*\")";
          }
          {
            name = "all_channels";
            value = "Title ~ \".*\"";
          }
          {
            name = "final_channel_lineup";
            value = "!all_channels! AND !not_red_button! AND !not_low_resolution!";
          }
        ];
        sources = [
          {
            inputs = [
              {
                name = "iptv-org";
                type = "m3u";
                url = "https://iptv-org.github.io/iptv/countries/uk.m3u";
              }
            ];
            targets = [
              {
                name = "iptv-org";
                output = [
                  {
                    type = "xtream";
                  }
                  {
                    type = "m3u";
                    filename = "iptv.m3u";
                  }
                  {
                    type = "hdhomerun";
                    username = "local";
                    device = "hdhr1";
                  }
                ];
                filter = "!final_channel_lineup!";
                options = {
                  ignore_logo = false;
                  share_live_streams = true;
                };
                mapping = [
                  "iptv-org"
                ];
              }
            ];
          }
        ];
      };
      description = ''
        Source definitions

        Refer to the [Tuliprox documentation] for available attributes

        [Tuliprox documentation]: https://github.com/euzu/tuliprox?tab=readme-ov-file#2-sourceyml
      '';
    };

    apiProxySettings = lib.mkOption {
      type = settingsFormat.type;
      example = {
        server = [
          {
            name = "default";
            protocol = "http";
            host = "192.169.1.9";
            port = 8901;
            timezone = "Europe/Paris";
            message = "Welcome to tuliprox";
          }
          {
            name = "external";
            protocol = "https";
            host = "tuliprox.mydomain.tv";
            port = 443;
            timezone = "Europe/Paris";
            message = "Welcome to tuliprox";
          }
        ];
        user = [
          {
            target = "xc_m3u";
            credentials = [
              {
                username = "test1";
                password = "secret1";
                token = "token1";
                proxy = "reverse";
                server = "default";
                exp_date = 1672705545;
                max_connections = 1;
                status = "Active";
              }
            ];
          }
        ];
      };
      description = ''
        Users and proxy configuration

        Refer to the [Tuliprox documentation] for available attributes

        [Tuliprox documentation]: https://github.com/euzu/tuliprox?tab=readme-ov-file#3-api-proxy-config
      '';
    };

    mappingSettings = lib.mkOption {
      type = settingsFormat.type;
      example = {
        mappings = {
          templates = [
            {
              name = "bbc";
              value = "Title ~ \"^BBC\"";
            }
            {
              name = "documentary";
              value = "(Group ~ \"(Documentary|Outdoor)\")";
            }
            {
              name = "entertainment";
              value = "Group ~ \"Entertainment\"";
            }
            {
              name = "pluto_tv";
              value = "(Caption ~ \"Pluto TV\") AND NOT(Caption ~ \"Sports\")";
            }
            {
              name = "business";
              value = "Group ~ \"Business\"";
            }
          ];
          mapping = [
            {
              id = "iptv-org";
              match_as_ascii = true;
              mapper = [
                {
                  filter = "!bbc!";
                  script = ''
                    @Group = "BBC"
                  '';
                }
                {
                  filter = "!documentary!";
                  script = ''
                    @Group = "Documentary"
                  '';
                }
                {
                  filter = "!entertainment!";
                  script = ''
                    @Group = "Entertainment"
                  '';
                }
                {
                  filter = "!pluto_tv!";
                  script = ''
                    @Group = "Pluto TV"
                  '';
                }
                {
                  filter = "!business!";
                  script = ''
                    @Group = "News"
                  '';
                }
                {
                  filter = "Input ~ \"iptv-org\"";
                  script = ''
                    @Caption = concat(@Caption, " (iptv-org)")
                  '';
                }
              ];
            }
          ];
        };
      };
      description = ''
        Templates configuration

        Refer to the [Tuliprox documentation] for available attributes

        [Tuliprox documentation]: https://github.com/euzu/tuliprox?tab=readme-ov-file#2-mappingyml
      '';
    };
  };

  config = lib.mkIf cfg.enable {
    services.tuliprox.systemSettings = {
      api = {
        host = lib.mkDefault "127.0.0.1";
        port = lib.mkDefault 8901;
        web_root = lib.mkDefault "${cfg.package}/web";
      };
      working_dir = lib.mkDefault "\${env:STATE_DIRECTORY}/data";
      backup_dir = lib.mkDefault "\${env:STATE_DIRECTORY}/backup";
      custom_stream_response_path = lib.mkDefault "${cfg.package}/resources";
    };
    services.tuliprox.sourceSettings.sources = lib.mkDefault [ ];
    services.tuliprox.apiProxySettings = {
      server = lib.mkDefault [
        {
          name = "default";
          protocol = "http";
          host = cfg.systemSettings.api.host;
          port = cfg.systemSettings.api.port;
          timezone = if config.time.timeZone != null then config.time.timeZone else "Etc/UTC";
          message = "Welcome to tuliprox";
        }
      ];
      user = lib.mkDefault [ ];
    };
    services.tuliprox.mappingSettings.mappings.mapping = lib.mkDefault [ ];

    systemd.services.tuliprox = {
      description = "Tuliprox server";

      serviceConfig = {
        ExecStart = utils.escapeSystemdExecArgs (
          [
            (lib.getExe cfg.package)
            "--server"
            "--config"
            systemSettingsYaml
            "--source"
            sourceSettingsYaml
            "--api-proxy"
            apiProxySettingsYaml
            "--mapping"
            mappingSettingsYaml
          ]
          ++ cfg.extraArgs
        );
        Restart = "always";

        DynamicUser = true;
        StateDirectory = "tuliprox";

        CapabilityBoundingSet = "";
        LockPersonality = true;
        MemoryDenyWriteExecute = true;
        PrivateDevices = true;
        PrivateUsers = true;
        ProcSubset = "pid";
        ProtectClock = true;
        ProtectControlGroups = true;
        ProtectHome = true;
        ProtectHostname = true;
        ProtectKernelLogs = true;
        ProtectKernelModules = true;
        ProtectKernelTunables = true;
        ProtectProc = "invisible";
        RestrictAddressFamilies = [
          "AF_UNIX"
          "AF_INET"
          "AF_INET6"
        ];
        RestrictNamespaces = true;
        RestrictRealtime = true;
        SystemCallArchitectures = "native";
        SystemCallFilter = [
          "@system-service"
          "~@privileged"
          "~@resources"
        ];
        UMask = "0066";
      };

      wantedBy = [ "multi-user.target" ];
    };
  };
}
+1 −0
Original line number Diff line number Diff line
@@ -1582,6 +1582,7 @@ in
  trilium-server = runTestOn [ "x86_64-linux" ] ./trilium-server.nix;
  tsm-client-gui = runTest ./tsm-client-gui.nix;
  ttyd = runTest ./web-servers/ttyd.nix;
  tuliprox = runTest ./tuliprox.nix;
  tuned = runTest ./tuned.nix;
  tuptime = runTest ./tuptime.nix;
  turbovnc-headless-server = runTest ./turbovnc-headless-server.nix;
+19 −0
Original line number Diff line number Diff line
{ lib, pkgs, ... }:
{
  name = "tuliprox";
  meta.maintainers = with lib.maintainers; [ nyanloutre ];

  nodes.machine =
    { pkgs, ... }:
    {
      services.tuliprox = {
        enable = true;
      };
    };

  testScript = ''
    machine.wait_for_unit("multi-user.target")
    machine.wait_for_open_port(8901)
    machine.succeed("curl -v -s http://127.0.0.1:8901/")
  '';
}
+84 −0
Original line number Diff line number Diff line
{
  lib,
  fetchFromGitHub,
  rustPlatform,
  pkg-config,
  openssl,
  ffmpeg,
  which,
  rustc,
  wasm-bindgen-cli_0_2_104,
  trunk,
  binaryen,
  dart-sass,
  nixosTests,
  nix-update-script,
}:

rustPlatform.buildRustPackage rec {
  pname = "tuliprox";
  version = "3.2.0";

  src = fetchFromGitHub {
    owner = "euzu";
    repo = "tuliprox";
    tag = "v${version}";
    hash = "sha256-G+bVKBAxviyJShq2BG4vjMiTzHhoYaiP6FXrSWeTvkU=";
  };

  nativeBuildInputs = [
    pkg-config
    ffmpeg
    which
    wasm-bindgen-cli_0_2_104
    trunk
    rustc.llvmPackages.lld
    binaryen
    dart-sass
  ];

  # Needed to get openssl-sys to use pkg-config.
  env = {
    OPENSSL_NO_VENDOR = 1;
    OPENSSL_LIB_DIR = "${lib.getLib openssl}/lib";
    OPENSSL_DIR = "${lib.getDev openssl}";
  };

  cargoHash = "sha256-bDQ4pDDTINTgotTen1/SxOZBmkUmbmmwmR4/nSoSf/A=";

  cargoBuildFlags = "--package tuliprox";

  postBuild = ''
    patchShebangs ./bin/build_resources.sh
    ./bin/build_resources.sh
    pushd frontend
    trunk build --offline --frozen --release
    popd
  '';

  checkFlags = [
    "--skip=processing::parser::xmltv::tests::normalize"
    "--skip=processing::parser::xtream::tests::test_read_json_file_into_struct"
    "--skip=repository::indexed_document::tests::test_read_xt"
  ];

  postInstall = ''
    cp -rf frontend/dist $out/web
    mkdir -p $out/resources
    cp -rf resources/*.ts $out/resources
  '';

  passthru = {
    tests = { inherit (nixosTests) tuliprox; };
    updateScript = nix-update-script { };
  };

  meta = {
    description = "Flexible IPTV playlist processor & proxy in Rust";
    homepage = "https://github.com/euzu/tuliprox";
    changelog = "https://github.com/euzu/tuliprox/blob/${src.tag}/CHANGELOG.md";
    mainProgram = "tuliprox";
    license = with lib.licenses; [ mit ];
    maintainers = with lib.maintainers; [ nyanloutre ];
  };
}