ersatztv: init at 25.8.0; nixos/ersatztv init module (#348655)

This commit is contained in:
Bruno BELANYI
2025-11-18 15:53:54 +00:00
committed by GitHub
9 changed files with 2325 additions and 0 deletions
+6
View File
@@ -1321,6 +1321,12 @@
githubId = 5892756;
name = "Alec Snyder";
};
allout58 = {
email = "jamesthollowell@gmail.com";
github = "allout58";
githubId = 2939703;
name = "James Hollowell";
};
allusive = {
email = "jasper@allusive.dev";
name = "Allusive";
@@ -194,6 +194,8 @@
- [nixbit](https://github.com/pbek/nixbit), a GUI application for updating your NixOS system from a Nix Flakes Git repository. Available as [programs.nixbit](#opt-programs.nixbit.enable).
- [ErsatzTV](https://ersatztv.org), a personal IPTV server. Available as [services.ersatztv](#opt-services.ersatztv.enable)
## Backward Incompatibilities {#sec-release-25.11-incompatibilities}
<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
+1
View File
@@ -833,6 +833,7 @@
./services/misc/dwm-status.nix
./services/misc/dysnomia.nix
./services/misc/errbot.nix
./services/misc/ersatztv.nix
./services/misc/etebase-server.nix
./services/misc/etesync-dav.nix
./services/misc/evdevremapkeys.nix
+133
View File
@@ -0,0 +1,133 @@
{
config,
pkgs,
lib,
...
}:
let
inherit (lib)
mkIf
getExe
maintainers
mkEnableOption
mkOption
mkPackageOption
;
inherit (lib.types)
str
path
bool
float
int
;
cfg = config.services.ersatztv;
defaultEnv = {
ETV_UI_PORT = 8409;
ETV_BASE_URL = "/";
};
in
{
options = {
services.ersatztv = {
enable = mkEnableOption "ErsatzTV";
package = mkPackageOption pkgs "ersatztv" { };
user = mkOption {
type = str;
default = "ersatztv";
description = "User account under which ErsatzTV runs.";
};
group = mkOption {
type = str;
default = "ersatztv";
description = "Group under which ErsatzTV runs.";
};
environment = mkOption {
type =
with lib.types;
attrsOf (oneOf [
str
int
float
bool
]);
default = defaultEnv;
example = {
ETV_UI_PORT = 8000;
ETV_STREAMING_PORT = 8001;
};
description = "Environment variables to set for the ErsatzTV service.";
};
baseUrl = mkOption {
type = str;
default = "/";
description = ''
Base URL to support reverse proxies that use paths (e.g. `/ersatztv`)
'';
};
openFirewall = mkOption {
type = bool;
default = false;
description = ''
Open the default ports in the firewall for the server.
'';
};
};
};
config = mkIf cfg.enable {
services.ersatztv.environment = lib.mapAttrs (_: lib.mkDefault) defaultEnv;
systemd = {
services.ersatztv = {
description = "ErsatzTV";
after = [ "network-online.target" ];
wants = [ "network-online.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "simple";
User = cfg.user;
Group = cfg.group;
DynamicUser = true;
UMask = "0077";
StateDirectory = "ersatztv";
WorkingDirectory = "/var/lib/ersatztv";
ExecStart = getExe cfg.package;
Restart = "on-failure";
};
# Set environment variables for the service, using known values for ETV_CONFIG_FOLDER and ETV_TRANSCODE_FOLDER, and allowing overrides from cfg.environment
environment = {
ETV_CONFIG_FOLDER = "/var/lib/ersatztv/config";
ETV_TRANSCODE_FOLDER = "/var/lib/ersatztv/transcode";
}
// cfg.environment;
};
};
users.users = mkIf (cfg.user == "ersatztv") {
ersatztv = {
inherit (cfg) group;
isSystemUser = true;
};
};
users.groups = mkIf (cfg.group == "ersatztv") { ersatztv = { }; };
networking.firewall = mkIf cfg.openFirewall {
allowedTCPPorts = [
cfg.environment.ETV_UI_PORT
];
};
};
meta.maintainers = with maintainers; [ allout58 ];
}
+1
View File
@@ -523,6 +523,7 @@ in
};
ergo = runTest ./ergo.nix;
ergochat = runTest ./ergochat.nix;
ersatztv = handleTest ./ersatztv.nix { };
esphome = runTest ./esphome.nix;
etc = pkgs.callPackage ../modules/system/etc/test.nix { inherit evalMinimalConfig; };
etcd = import ./etcd/default.nix { inherit pkgs runTest; };
+21
View File
@@ -0,0 +1,21 @@
import ./make-test-python.nix (
{ lib, ... }:
{
name = "ersatztv";
meta.maintainers = with lib.maintainers; [ allout58 ];
nodes.machine =
{ ... }:
{
services.ersatztv.enable = true;
};
# ErsatzTV doesn't really have an API to speak of currently, so just check if it responds at all
testScript = ''
machine.wait_for_unit("ersatztv.service")
machine.wait_for_open_port(8409)
machine.succeed("curl --fail http://localhost:8409/")
'';
}
)
File diff suppressed because it is too large Load Diff
+53
View File
@@ -0,0 +1,53 @@
{
lib,
fetchFromGitHub,
dotnetCorePackages,
buildDotnetModule,
ffmpeg,
which,
}:
buildDotnetModule rec {
pname = "ersatztv";
version = "25.8.0";
src = fetchFromGitHub {
owner = "ErsatzTV";
repo = "ErsatzTV";
rev = "v${version}";
sha256 = "sha256-FuuX/SxhzzUn7ELJDXJuILkl3ubR3V+5hQwILvZZrFg=";
};
buildInputs = [ ffmpeg ];
projectFile = "ErsatzTV/ErsatzTV.csproj";
executables = [
"ErsatzTV"
"ErsatzTV.Scanner"
];
nugetDeps = ./nuget-deps.json;
dotnet-sdk = dotnetCorePackages.sdk_9_0;
dotnet-runtime = dotnetCorePackages.aspnetcore_9_0;
# ETV uses `which` to find `ffmpeg` and `ffprobe`
makeWrapperArgs = [
"--suffix"
"PATH"
":"
"${lib.makeBinPath [
ffmpeg
which
]}"
];
passthru.updateScript = ./update.sh;
meta = with lib; {
description = "Stream custom live channels using your own media";
homepage = "https://ersatztv.org/";
license = licenses.zlib;
maintainers = with maintainers; [ allout58 ];
mainProgram = "ErsatzTV";
platforms = dotnet-runtime.meta.platforms;
};
}
+16
View File
@@ -0,0 +1,16 @@
#!/usr/bin/env nix-shell
#!nix-shell -I nixpkgs=./. -i bash -p curl jq common-updater-scripts gnused nix coreutils
set -euo pipefail
latestVersion="$(curl -s ${GITHUB_TOKEN:+-u ":$GITHUB_TOKEN"} "https://api.github.com/repos/ersatztv/ersatztv/releases?per_page=1" | jq -r ".[0].tag_name" | sed 's/^v//')"
currentVersion=$(nix-instantiate --eval -E "with import ./. {}; ersatztv.version or (lib.getVersion ersatztv)" | tr -d '"')
if [[ "$currentVersion" == "$latestVersion" ]]; then
echo "ersatztv is up-to-date: $currentVersion"
exit 0
fi
update-source-version ersatztv "$latestVersion"
$(nix-build . -A ersatztv.fetch-deps --no-out-link)