pyload-ng: drop (#502033)

This commit is contained in:
Thomas Gerbet
2026-04-02 06:46:40 +00:00
committed by GitHub
15 changed files with 9 additions and 421 deletions
@@ -164,7 +164,7 @@ The pre-existing `services.ankisyncd` has been marked deprecated and will be dro
- [prometheus-nats-exporter](https://github.com/nats-io/prometheus-nats-exporter), a Prometheus exporter for NATS. Available as [services.prometheus.exporters.nats](#opt-services.prometheus.exporters.nats.enable).
- [pyLoad](https://pyload.net/), a FOSS download manager written in Python. Available as [services.pyload](#opt-services.pyload.enable).
- [pyLoad](https://pyload.net/), a FOSS download manager written in Python. Available as `services.pyload`.
- [Python Matter Server](https://github.com/home-assistant-libs/python-matter-server), a
Matter Controller Server exposing websocket connections for use with other services, notably Home Assistant.
@@ -129,6 +129,8 @@
- `services.statsd` has been removed because the packages it relies on do not exist anymore in nixpkgs.
- `services.pyload` has been removed because the package it relies on does not exist anymore in nixpkgs due to vulnerabilities and being unmaintained.
- `services.tandoor-recipes` now uses a sub-directory for media files by default starting with `26.05`. Existing setups should move media files out of the data directory and adjust `services.tandoor-recipes.extraConfig.MEDIA_ROOT` accordingly. See [Migrating media files for pre 26.05 installations](#module-services-tandoor-recipes-migrating-media).
- `rustic` was upgraded to `0.11.x`, which contains breaking [changes to command-line parameters and configuration file](https://rustic.cli.rs/docs/breaking_changes.html#0110).
-1
View File
@@ -1347,7 +1347,6 @@
./services/networking/pptpd.nix
./services/networking/privoxy.nix
./services/networking/prosody.nix
./services/networking/pyload.nix
./services/networking/quassel.nix
./services/networking/quicktun.nix
./services/networking/r53-ddns.nix
+3
View File
@@ -486,6 +486,9 @@ in
(mkRemovedOptionModule [ "programs" "spacefm" ] ''
spacefm has been removed since it was unmaintained upstream.
'')
(mkRemovedOptionModule [ "services" "pyload" ] ''
services.pyload has been removed since the pyload-ng package had vulnerabilities and was unmaintained in nixpkgs.
'')
# Do NOT add any option renames here, see top of the file
];
}
@@ -1,176 +0,0 @@
{
config,
lib,
pkgs,
utils,
...
}:
let
cfg = config.services.pyload;
stateDir = "/var/lib/pyload";
in
{
meta.maintainers = with lib.maintainers; [ ambroisie ];
options = with lib; {
services.pyload = {
enable = mkEnableOption "pyLoad download manager";
package = mkPackageOption pkgs "pyLoad" { default = [ "pyload-ng" ]; };
listenAddress = mkOption {
type = types.str;
default = "localhost";
example = "0.0.0.0";
description = "Address to listen on for the web UI.";
};
port = mkOption {
type = types.port;
default = 8000;
example = 9876;
description = "Port to listen on for the web UI.";
};
downloadDirectory = mkOption {
type = types.path;
default = "${stateDir}/downloads";
example = "/mnt/downloads";
description = "Directory to store downloads.";
};
user = mkOption {
type = types.str;
default = "pyload";
description = "User under which pyLoad runs, and which owns the download directory.";
};
group = mkOption {
type = types.str;
default = "pyload";
description = "Group under which pyLoad runs, and which owns the download directory.";
};
credentialsFile = mkOption {
type = with types; nullOr path;
default = null;
example = "/run/secrets/pyload-credentials.env";
description = ''
File containing {env}`PYLOAD_DEFAULT_USERNAME` and
{env}`PYLOAD_DEFAULT_PASSWORD` in the format of an `EnvironmentFile=`,
as described by {manpage}`systemd.exec(5)`.
If not given, they default to the username/password combo of
pyload/pyload.
'';
};
};
};
config = lib.mkIf cfg.enable {
systemd.tmpfiles.settings.pyload = {
${cfg.downloadDirectory}.d = { inherit (cfg) user group; };
};
systemd.services.pyload = {
description = "pyLoad download manager";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
# NOTE: unlike what the documentation says, it looks like `HOME` is not
# defined with this service definition...
# Since pyload tries to do the equivalent of `cd ~`, it needs to be able
# to resolve $HOME, which fails when `RootDirectory` is set.
# FIXME: check if `SetLoginEnvironment` fixes this issue in version 255
environment = {
HOME = stateDir;
PYLOAD__WEBUI__HOST = cfg.listenAddress;
PYLOAD__WEBUI__PORT = toString cfg.port;
};
serviceConfig = {
ExecStart = utils.escapeSystemdExecArgs [
(lib.getExe cfg.package)
"--userdir"
"${stateDir}/config"
"--storagedir"
cfg.downloadDirectory
];
User = cfg.user;
Group = cfg.group;
EnvironmentFile = lib.optional (cfg.credentialsFile != null) cfg.credentialsFile;
StateDirectory = "pyload";
WorkingDirectory = stateDir;
RuntimeDirectory = "pyload";
RuntimeDirectoryMode = "0700";
RootDirectory = "/run/pyload";
BindReadOnlyPaths = [
builtins.storeDir # Needed to run the python interpreter
];
BindPaths = [
cfg.downloadDirectory
];
# Hardening options
LockPersonality = true;
NoNewPrivileges = true;
PrivateDevices = true;
PrivateMounts = true;
PrivateTmp = true;
PrivateUsers = true;
ProcSubset = "pid";
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
ProtectSystem = "strict";
RemoveIPC = true;
RestrictAddressFamilies = "AF_INET AF_INET6 AF_UNIX";
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
"~@resources"
"~@privileged"
];
UMask = "0002";
CapabilityBoundingSet = [
"~CAP_BLOCK_SUSPEND"
"~CAP_BPF"
"~CAP_CHOWN"
"~CAP_IPC_LOCK"
"~CAP_KILL"
"~CAP_LEASE"
"~CAP_LINUX_IMMUTABLE"
"~CAP_NET_ADMIN"
"~CAP_SYS_ADMIN"
"~CAP_SYS_BOOT"
"~CAP_SYS_CHROOT"
"~CAP_SYS_NICE"
"~CAP_SYS_PACCT"
"~CAP_SYS_PTRACE"
"~CAP_SYS_RESOURCE"
"~CAP_SYS_TTY_CONFIG"
];
};
};
users.users.pyload = lib.mkIf (cfg.user == "pyload") {
isSystemUser = true;
group = cfg.group;
home = stateDir;
};
users.groups.pyload = lib.mkIf (cfg.group == "pyload") { };
};
}
-1
View File
@@ -1348,7 +1348,6 @@ in
pulseaudio = discoverTests (import ./pulseaudio.nix);
pulseaudio-tcp = runTest ./pulseaudio-tcp.nix;
pykms = runTest ./pykms.nix;
pyload = runTest ./pyload.nix;
qbittorrent = runTest ./qbittorrent.nix;
qboot = handleTestOn [ "x86_64-linux" "i686-linux" ] ./qboot.nix { };
qemu-vm-credentials-fwcfg = runTest {
-36
View File
@@ -1,36 +0,0 @@
{ lib, ... }:
{
name = "pyload";
meta.maintainers = with lib.maintainers; [ ambroisie ];
nodes = {
machine =
{ ... }:
{
services.pyload = {
enable = true;
listenAddress = "0.0.0.0";
port = 9876;
};
networking.firewall.allowedTCPPorts = [ 9876 ];
};
client = { };
};
testScript = ''
start_all()
machine.wait_for_unit("pyload.service")
with subtest("Web interface accessible locally"):
machine.wait_until_succeeds("curl -fs localhost:9876")
client.wait_for_unit("network.target")
with subtest("Web interface accessible from a different machine"):
client.wait_until_succeeds("curl -fs machine:9876")
'';
}
@@ -1,15 +0,0 @@
diff --git a/src/pyload/core/__init__.py b/src/pyload/core/__init__.py
index 4324fc700..f7fcd66ec 100644
--- a/src/pyload/core/__init__.py
+++ b/src/pyload/core/__init__.py
@@ -46,8 +46,8 @@ class Exit(Exception):
# improve external scripts
class Core:
LOCALE_DOMAIN = APPID
- DEFAULT_USERNAME = APPID
- DEFAULT_PASSWORD = APPID
+ DEFAULT_USERNAME = os.getenv("PYLOAD_DEFAULT_USERNAME", APPID)
+ DEFAULT_PASSWORD = os.getenv("PYLOAD_DEFAULT_PASSWORD", APPID)
DEFAULT_DATADIR = os.path.join(
os.getenv("APPDATA") or USERHOMEDIR, "pyLoad" if os.name == "nt" else ".pyload"
)
@@ -1,18 +0,0 @@
diff --git a/src/pyload/core/__init__.py b/src/pyload/core/__init__.py
index 4324fc700..5d915a85e 100644
--- a/src/pyload/core/__init__.py
+++ b/src/pyload/core/__init__.py
@@ -128,6 +128,13 @@ class Core:
else:
self._debug = max(0, int(debug))
+ # Allow setting any option declaratively, for the NixOS module
+ for env, value in os.environ.items():
+ if not env.startswith("PYLOAD__"):
+ continue
+ section, opt = env.removeprefix("PYLOAD__").lower().split("__")
+ self.config.set(section, opt, value)
+
# If no argument set, read storage dir from config file,
# otherwise save setting to config dir
if storagedir is None:
-72
View File
@@ -1,72 +0,0 @@
{
lib,
fetchPypi,
nixosTests,
python3,
}:
python3.pkgs.buildPythonApplication (finalAttrs: {
version = "0.5.0b3.dev88";
pname = "pyload-ng";
pyproject = true;
src = fetchPypi {
inherit (finalAttrs) version;
# The uploaded tarball uses an underscore in recent releases
pname = "pyload_ng";
hash = "sha256-6YVYXiYxUkpQmDG/aGEgBlJy2oUGCNDkIsUt0TRcaro=";
};
patches = [
# Makes it possible to change the default username/password in the module
./declarative-default-user.patch
# Makes it possible to change the configuration through environment variables
# in the NixOS module (aimed mostly at listen address/port)
./declarative-env-config.patch
];
postPatch = ''
# relax version bounds
sed -i -E 's/([A-z0-9]*)~=[^;]*(.*)/\1\2/' setup.cfg
'';
dependencies = with python3.pkgs; [
bitmath
certifi
cheroot
cryptography
dukpy
filetype
flask
flask-babel
flask-caching
flask-compress
flask-session
flask-themes2
pycurl
semver
setuptools
];
optional-dependencies = {
plugins = with python3.pkgs; [
beautifulsoup4 # for some plugins
colorlog # colorful console logging
pillow # for some CAPTCHA plugin
send2trash # send some files to trash instead of deleting them
slixmpp # XMPP plugin
];
};
passthru.tests = {
inherit (nixosTests) pyload;
};
meta = {
description = "Free and open-source download manager with support for 1-click-hosting sites";
homepage = "https://github.com/pyload/pyload";
license = lib.licenses.agpl3Plus;
maintainers = with lib.maintainers; [ ruby0b ];
mainProgram = "pyload";
};
})
@@ -1,64 +0,0 @@
{
lib,
stdenv,
fetchFromGitHub,
buildPythonPackage,
setuptools,
mutf8,
webassets,
pytestCheckHook,
mock,
}:
buildPythonPackage rec {
pname = "dukpy";
version = "0.5.1";
pyproject = true;
src = fetchFromGitHub {
owner = "amol-";
repo = "dukpy";
tag = version;
hash = "sha256-ZoBkCpilqPwDy0njwXqUIVgKt16jDCdnbDk7EfxzWOM=";
};
postPatch = ''
substituteInPlace tests/test_webassets_filter.py \
--replace-fail "class PyTestTemp" "class _Temp" \
--replace-fail "PyTestTemp" "Temp"
'';
build-system = [ setuptools ];
dependencies = [ mutf8 ];
optional-dependencies = {
webassets = [ webassets ];
};
nativeCheckInputs = [
pytestCheckHook
mock
]
++ optional-dependencies.webassets;
disabledTests = [ "test_installer" ];
preCheck = ''
rm -r dukpy
'';
pythonImportsCheck = [ "dukpy" ];
meta = {
description = "Simple JavaScript interpreter for Python";
homepage = "https://github.com/amol-/dukpy";
changelog = "https://github.com/amol-/dukpy/releases/tag/${src.tag}";
license = lib.licenses.mit;
maintainers = with lib.maintainers; [ ruby0b ];
mainProgram = "dukpy";
# error: 'TARGET_OS_BRIDGE' is not defined, evaluates to 0 [-Werror,-Wundef-prefix=TARGET_OS_]
# https://github.com/amol-/dukpy/issues/82
broken = stdenv.cc.isClang;
};
}
@@ -1,33 +0,0 @@
{
lib,
buildPythonPackage,
fetchPypi,
setuptools,
flask,
pytestCheckHook,
}:
buildPythonPackage rec {
pname = "flask-themes2";
version = "1.0.1";
pyproject = true;
src = fetchPypi {
pname = "Flask-Themes2";
inherit version;
hash = "sha256-gsMgQQXjhDfQRhm7H0kBy8jKxd75WY+PhHR6Rk/PUPs=";
};
nativeBuildInputs = [ setuptools ];
propagatedBuildInputs = [ flask ];
nativeCheckInputs = [ pytestCheckHook ];
meta = {
description = "Easily theme your Flask app";
homepage = "https://github.com/sysr-q/flask-themes2";
license = lib.licenses.mit;
maintainers = with lib.maintainers; [ ruby0b ];
};
}
+1
View File
@@ -1675,6 +1675,7 @@ mapAliases {
purple-vk-plugin = throw "'purple-vk-plugin' has been removed as upstream repository was deleted and no active forks are found."; # Added 2025-09-17
purple-xmpp-http-upload = throw "'purple-xmpp-http-upload' has been renamed to/replaced by 'pidginPackages.purple-xmpp-http-upload'"; # Converted to throw 2025-10-27
pyCA = warnAlias "'pyCA' was renamed to 'pyca'" pyca; # Added 2026-02-12
pyload-ng = throw "'pyload-ng' has been removed due to vulnerabilities and being unmaintained"; # Added 2026-03-21
pyo3-pack = throw "'pyo3-pack' has been renamed to/replaced by 'maturin'"; # Converted to throw 2025-10-27
pypolicyd-spf = throw "'pypolicyd-spf' has been renamed to/replaced by 'spf-engine'"; # Converted to throw 2025-10-27
python3Full = throw "python3Full has been removed. Bluetooth support is now enabled by default. The tkinter package is available within the package set."; # Added 2025-08-30
+2
View File
@@ -181,6 +181,7 @@ mapAliases {
docker_pycreds = throw "'docker_pycreds' has been renamed to/replaced by 'docker-pycreds'"; # Converted to throw 2025-10-29
dogpile_cache = throw "'dogpile_cache' has been renamed to/replaced by 'dogpile-cache'"; # Converted to throw 2025-10-29
duckduckgo-search = throw "duckduckgo-search was renamed to ddgs, use ddgs instead"; # added 2025-10-20
dukpy = throw "'dukpy' was removed as the only consumer pyload-ng was removed"; # added 2026-03-21
easyeda2ato = throw "easyeda2ato as been removed in favor of atopile-easyda2kicad"; # added 2025-06-08
EasyProcess = throw "'EasyProcess' has been renamed to/replaced by 'easyprocess'"; # Converted to throw 2025-10-29
editdistance-s = throw "editdistance-s has been removed since it was added solely for the identity package, which has moved on to ukkonen"; # added 2025-08-04
@@ -204,6 +205,7 @@ mapAliases {
filesplit = throw "filesplit has been removed, since it is unmaintained"; # added 2025-08-20
flask-security-too = throw "'flask-security-too' has been renamed to/replaced by 'flask-security'"; # Converted to throw 2025-10-29
flask-silk = throw "flask-silk was removed, as it is unmaintained since 2018."; # added 2025-05-25
flask-themes2 = throw "'flask-themes2' was removed as the only consumer pyload-ng was removed"; # added 2026-03-21
flask_assets = throw "'flask_assets' has been renamed to/replaced by 'flask-assets'"; # Converted to throw 2025-10-29
flask_elastic = throw "'flask_elastic' has been renamed to/replaced by 'flask-elastic'"; # Converted to throw 2025-10-29
flask_login = throw "'flask_login' has been renamed to/replaced by 'flask-login'"; # Converted to throw 2025-10-29
-4
View File
@@ -4763,8 +4763,6 @@ self: super: with self; {
dufte = callPackage ../development/python-modules/dufte { };
dukpy = callPackage ../development/python-modules/dukpy { };
dulwich = callPackage ../development/python-modules/dulwich { inherit (pkgs) gnupg; };
dunamai = callPackage ../development/python-modules/dunamai { };
@@ -5727,8 +5725,6 @@ self: super: with self; {
flask-themer = callPackage ../development/python-modules/flask-themer { };
flask-themes2 = callPackage ../development/python-modules/flask-themes2 { };
flask-unsign = callPackage ../development/python-modules/flask-unsign { };
flask-versioned = callPackage ../development/python-modules/flask-versioned { };