parent
3dbdacdd6e
commit
ecaf765bb5
11 changed files with 405 additions and 0 deletions
|
@ -147,6 +147,7 @@ in {
|
||||||
prowlarr.reverseProxy = "${nosIP}:9696";
|
prowlarr.reverseProxy = "${nosIP}:9696";
|
||||||
radarr.reverseProxy = "${nosIP}:7878";
|
radarr.reverseProxy = "${nosIP}:7878";
|
||||||
sonarr.reverseProxy = "${nosIP}:8989";
|
sonarr.reverseProxy = "${nosIP}:8989";
|
||||||
|
kapowarr.reverseProxy = "${nosIP}:5676";
|
||||||
|
|
||||||
jdownloader2 = {
|
jdownloader2 = {
|
||||||
subDirName = "jd2";
|
subDirName = "jd2";
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
{...}: {
|
{...}: {
|
||||||
imports = [
|
imports = [
|
||||||
./jdownloader2
|
./jdownloader2
|
||||||
|
./kapowarr
|
||||||
./komga
|
./komga
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
11
configurations/nos/modules/comics/kapowarr/default.nix
Normal file
11
configurations/nos/modules/comics/kapowarr/default.nix
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{mainUser, ...}: {
|
||||||
|
imports = [./module.nix];
|
||||||
|
|
||||||
|
services.kapowarr = {
|
||||||
|
enable = true;
|
||||||
|
port = 5676;
|
||||||
|
|
||||||
|
user = mainUser;
|
||||||
|
group = "users";
|
||||||
|
};
|
||||||
|
}
|
116
configurations/nos/modules/comics/kapowarr/module.nix
Normal file
116
configurations/nos/modules/comics/kapowarr/module.nix
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
inherit
|
||||||
|
(lib)
|
||||||
|
getExe
|
||||||
|
mkEnableOption
|
||||||
|
mkIf
|
||||||
|
mkOption
|
||||||
|
mkPackageOption
|
||||||
|
types
|
||||||
|
;
|
||||||
|
|
||||||
|
cfg = config.services.kapowarr;
|
||||||
|
in {
|
||||||
|
options.services.kapowarr = {
|
||||||
|
enable = mkEnableOption "kapowarr";
|
||||||
|
package = mkPackageOption pkgs.selfPackages "kapowarr" {};
|
||||||
|
|
||||||
|
user = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "kapowarr";
|
||||||
|
description = "The user account under which Kapowarr runs.";
|
||||||
|
};
|
||||||
|
|
||||||
|
group = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "kapowarr";
|
||||||
|
description = "The group under which Kapowarr runs.";
|
||||||
|
};
|
||||||
|
|
||||||
|
port = mkOption {
|
||||||
|
type = types.port;
|
||||||
|
default = 5656;
|
||||||
|
description = "Port where kapowarr should listen for incoming requests.";
|
||||||
|
};
|
||||||
|
|
||||||
|
dataDir = mkOption {
|
||||||
|
type = types.path;
|
||||||
|
default = "/var/lib/kapowarr/";
|
||||||
|
description = "The directory where Kapowarr stores its data files.";
|
||||||
|
};
|
||||||
|
|
||||||
|
downloadDir = mkOption {
|
||||||
|
type = types.path;
|
||||||
|
default = "${cfg.dataDir}/temp_downloads";
|
||||||
|
defaultText = "/var/lib/kapowarr/temp_downloads";
|
||||||
|
description = "The directory where Kapowarr stores its downloaded files.";
|
||||||
|
};
|
||||||
|
|
||||||
|
logDir = mkOption {
|
||||||
|
type = types.path;
|
||||||
|
default = cfg.dataDir;
|
||||||
|
defaultText = "/var/lib/kapowarr";
|
||||||
|
description = "The directory where Kapowarr stores its log file.";
|
||||||
|
};
|
||||||
|
|
||||||
|
openFirewall = mkEnableOption "Open ports in the firewall for Kapowarr.";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
systemd.services.kapowarr = {
|
||||||
|
description = "Kapowarr";
|
||||||
|
after = ["network.target"];
|
||||||
|
wantedBy = ["multi-user.target"];
|
||||||
|
|
||||||
|
environment = {
|
||||||
|
KAPOWARR_PORT = toString cfg.port;
|
||||||
|
KAPOWARR_LOG_DIR = cfg.logDir;
|
||||||
|
KAPOWARR_STATE_DIR = cfg.dataDir;
|
||||||
|
KAPOWARR_DOWNLOAD_DIR = cfg.downloadDir;
|
||||||
|
};
|
||||||
|
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "simple";
|
||||||
|
User = cfg.user;
|
||||||
|
Group = cfg.group;
|
||||||
|
StateDirectory = mkIf (cfg.dataDir == "/var/lib/kapowar") "kapowarr";
|
||||||
|
ExecStart = "${getExe cfg.package} -d ${cfg.dataDir}";
|
||||||
|
|
||||||
|
# Hardening from komga service
|
||||||
|
RemoveIPC = true;
|
||||||
|
NoNewPrivileges = true;
|
||||||
|
CapabilityBoundingSet = "";
|
||||||
|
SystemCallFilter = ["@system-service"];
|
||||||
|
ProtectSystem = "full";
|
||||||
|
PrivateTmp = true;
|
||||||
|
ProtectProc = "invisible";
|
||||||
|
ProtectClock = true;
|
||||||
|
ProcSubset = "pid";
|
||||||
|
PrivateUsers = true;
|
||||||
|
PrivateDevices = true;
|
||||||
|
ProtectHostname = true;
|
||||||
|
ProtectKernelTunables = true;
|
||||||
|
RestrictAddressFamilies = [
|
||||||
|
"AF_INET"
|
||||||
|
"AF_INET6"
|
||||||
|
"AF_NETLINK"
|
||||||
|
];
|
||||||
|
LockPersonality = true;
|
||||||
|
RestrictNamespaces = true;
|
||||||
|
ProtectKernelLogs = true;
|
||||||
|
ProtectControlGroups = true;
|
||||||
|
ProtectKernelModules = true;
|
||||||
|
SystemCallArchitectures = "native";
|
||||||
|
RestrictSUIDSGID = true;
|
||||||
|
RestrictRealtime = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
networking.firewall = mkIf cfg.openFirewall {allowedTCPPorts = [cfg.port];};
|
||||||
|
};
|
||||||
|
}
|
|
@ -19,6 +19,8 @@
|
||||||
|
|
||||||
jmusicbot = final.callPackage ./jmusicbot {};
|
jmusicbot = final.callPackage ./jmusicbot {};
|
||||||
|
|
||||||
|
kapowarr = import ./kapowarr final;
|
||||||
|
|
||||||
komf = final.callPackage ./komf {};
|
komf = final.callPackage ./komf {};
|
||||||
|
|
||||||
libratbag = final.callPackage ./libratbag {
|
libratbag = final.callPackage ./libratbag {
|
||||||
|
|
17
packages/kapowarr/bencoding/default.nix
Normal file
17
packages/kapowarr/bencoding/default.nix
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
# nix build inputs
|
||||||
|
buildPythonPackage,
|
||||||
|
fetchPypi,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
pname = "bencoding";
|
||||||
|
version = "0.2.6";
|
||||||
|
in
|
||||||
|
buildPythonPackage {
|
||||||
|
inherit pname version;
|
||||||
|
|
||||||
|
src = fetchPypi {
|
||||||
|
inherit pname version;
|
||||||
|
hash = "sha256-Q8zjHUhj4p1rxhFVHU6fJlK+KZXp1eFbRtg4PxgNREA=";
|
||||||
|
};
|
||||||
|
}
|
14
packages/kapowarr/default.nix
Normal file
14
packages/kapowarr/default.nix
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
# nix build inputs
|
||||||
|
python3Packages,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
pyPkgs = python3Packages.override {
|
||||||
|
overrides = pyFinal: pyPrev: {
|
||||||
|
bencoding = pyFinal.callPackage ./bencoding {};
|
||||||
|
tenacity = pyFinal.callPackage ./tenacity {};
|
||||||
|
typing-extensions = pyFinal.callPackage ./typing-extensions {};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
pyPkgs.callPackage ./main {}
|
145
packages/kapowarr/main/default.nix
Normal file
145
packages/kapowarr/main/default.nix
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
{
|
||||||
|
# nix build inputs
|
||||||
|
lib,
|
||||||
|
buildPythonApplication,
|
||||||
|
fetchFromGitHub,
|
||||||
|
python,
|
||||||
|
# deps
|
||||||
|
aiohttp,
|
||||||
|
beautifulsoup4,
|
||||||
|
bencoding, # from overrides
|
||||||
|
flask,
|
||||||
|
flask-socketio,
|
||||||
|
pycryptodome,
|
||||||
|
requests,
|
||||||
|
setuptools,
|
||||||
|
simplejson,
|
||||||
|
tenacity, # from overrides
|
||||||
|
typing-extensions, # from overrides
|
||||||
|
waitress,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
pname = "kapowarr";
|
||||||
|
version = "1.1.1";
|
||||||
|
in
|
||||||
|
buildPythonApplication {
|
||||||
|
inherit pname version;
|
||||||
|
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "Casvt";
|
||||||
|
repo = "Kapowarr";
|
||||||
|
rev = "V${version}";
|
||||||
|
hash = "sha256-EeDzgi37f0cA86lQ1Z6hzLgpE3ORfz0YPoMWp5R4uPs=";
|
||||||
|
};
|
||||||
|
|
||||||
|
patches = [./raise-errors.patch];
|
||||||
|
|
||||||
|
postPatch = ''
|
||||||
|
# Insert import for following substituteInPlace
|
||||||
|
sed -i '/# -\*- coding: utf-8 -\*-/a from os import environ' ./backend/base/logging.py
|
||||||
|
|
||||||
|
substituteInPlace ./backend/base/logging.py --replace-fail \
|
||||||
|
"return folder_path(Constants.LOGGER_FILENAME)" \
|
||||||
|
"return f\"{environ.get('KAPOWARR_LOG_DIR')}/{Constants.LOGGER_FILENAME}\""
|
||||||
|
|
||||||
|
substituteInPlace ./backend/internals/settings.py \
|
||||||
|
--replace-fail \
|
||||||
|
"from os import urandom" \
|
||||||
|
"from os import urandom, environ" \
|
||||||
|
--replace-fail \
|
||||||
|
"port: int = 5656" \
|
||||||
|
"port: int = int(environ.get('KAPOWARR_PORT'))" \
|
||||||
|
--replace-fail \
|
||||||
|
"download_folder: str = folder_path('temp_downloads')" \
|
||||||
|
"download_folder: str = environ.get('KAPOWARR_DOWNLOAD_DIR')" \
|
||||||
|
--replace-fail \
|
||||||
|
"filename = folder_path('frontend', 'static', 'json', 'pwa_manifest.json')" \
|
||||||
|
"filename = f\"{environ.get('KAPOWARR_STATE_DIR')}/pwa_manifest.json\""
|
||||||
|
'';
|
||||||
|
|
||||||
|
build-system = [setuptools];
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
typing-extensions
|
||||||
|
requests
|
||||||
|
beautifulsoup4
|
||||||
|
flask
|
||||||
|
waitress
|
||||||
|
pycryptodome
|
||||||
|
tenacity
|
||||||
|
bencoding
|
||||||
|
simplejson
|
||||||
|
aiohttp
|
||||||
|
flask-socketio
|
||||||
|
];
|
||||||
|
|
||||||
|
preBuild = ''
|
||||||
|
cat > setup.py << EOF
|
||||||
|
from setuptools import setup, find_packages, find_namespace_packages
|
||||||
|
|
||||||
|
with open('requirements.txt') as f:
|
||||||
|
install_requires = f.read().splitlines()
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name='${pname}',
|
||||||
|
version = '${version}',
|
||||||
|
install_requires=install_requires,
|
||||||
|
packages=[
|
||||||
|
'frontend',
|
||||||
|
'backend',
|
||||||
|
'backend.base',
|
||||||
|
'backend.features',
|
||||||
|
'backend.implementations',
|
||||||
|
'backend.implementations.torrent_clients',
|
||||||
|
'backend.internals',
|
||||||
|
'backend.lib',
|
||||||
|
],
|
||||||
|
scripts=[
|
||||||
|
'Kapowarr.py'
|
||||||
|
],
|
||||||
|
)
|
||||||
|
EOF
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Use XDG-ish dirs for configuration. These would otherwise be in the kapowarr package.
|
||||||
|
#
|
||||||
|
# Using --run as `makeWrapper` evaluates variables for --set and --set-default at build
|
||||||
|
# time and then single quotes the vars in the wrapper, thus they wouldn't get expanded.
|
||||||
|
# But using --run allows setting default vars that are evaluated on run and not during
|
||||||
|
# build time.
|
||||||
|
makeWrapperArgs = [
|
||||||
|
"--set-default KAPOWARR_PORT 5656"
|
||||||
|
''
|
||||||
|
--run "OUTDIR=\"$out\""
|
||||||
|
--run '
|
||||||
|
configDir="''${XDG_CONFIG_HOME:-$HOME/.config}/kapowarr"
|
||||||
|
export KAPOWARR_STATE_DIR="''${KAPOWARR_STATE_DIR-$configDir}"
|
||||||
|
export KAPOWARR_LOG_DIR="''${KAPOWARR_LOG_DIR-$configDir}"
|
||||||
|
export KAPOWARR_DOWNLOAD_DIR="''${KAPOWARR_DOWNLOAD_DIR-$configDir/temp_downloads}"
|
||||||
|
mkdir -p "$KAPOWARR_STATE_DIR" "$KAPOWARR_LOG_DIR"
|
||||||
|
|
||||||
|
if [ ! -f "$KAPOWARR_STATE_DIR/pwa_manifest.json" ]; then
|
||||||
|
cat "$OUTDIR/${python.sitePackages}/frontend/static/json/pwa_manifest.json" > "$KAPOWARR_STATE_DIR/pwa_manifest.json"
|
||||||
|
fi
|
||||||
|
'
|
||||||
|
''
|
||||||
|
];
|
||||||
|
|
||||||
|
postFixup = ''
|
||||||
|
# I prefer a clean name for the executable
|
||||||
|
mv $out/bin/Kapowarr.py $out/bin/${pname}
|
||||||
|
|
||||||
|
# Add missing resources that Kapowarr uses at runtime in sitePackages
|
||||||
|
cp -r ./frontend/{static,templates} "$out/${python.sitePackages}/frontend"
|
||||||
|
'';
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
mainProgram = pname;
|
||||||
|
license = lib.licenses.gpl3Only;
|
||||||
|
homepage = "https://casvt.github.io/Kapowarr";
|
||||||
|
description = ''
|
||||||
|
Kapowarr is a software to build and manage a comic book library,
|
||||||
|
fitting in the *arr suite of software
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
26
packages/kapowarr/main/raise-errors.patch
Normal file
26
packages/kapowarr/main/raise-errors.patch
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
Kapowarr.py | 9 +++++++--
|
||||||
|
1 file changed, 7 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/Kapowarr.py b/Kapowarr.py
|
||||||
|
index 0e9da56..306976c 100644
|
||||||
|
--- a/Kapowarr.py
|
||||||
|
+++ b/Kapowarr.py
|
||||||
|
@@ -185,8 +185,13 @@ if __name__ == "__main__":
|
||||||
|
db_folder=db_folder
|
||||||
|
)
|
||||||
|
|
||||||
|
- except ValueError:
|
||||||
|
- parser.error("The value for -d/--DatabaseFolder is not a folder")
|
||||||
|
+ except ValueError as e:
|
||||||
|
+ if e.args and e.args[0] == 'Database location is not a folder':
|
||||||
|
+ parser.error(
|
||||||
|
+ "The value for -d/--DatabaseFolder is not a folder"
|
||||||
|
+ )
|
||||||
|
+ else:
|
||||||
|
+ raise e
|
||||||
|
|
||||||
|
else:
|
||||||
|
rc = Kapowarr()
|
||||||
|
--
|
||||||
|
2.48.1
|
||||||
|
|
49
packages/kapowarr/tenacity/default.nix
Normal file
49
packages/kapowarr/tenacity/default.nix
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
{
|
||||||
|
# nix build inputs
|
||||||
|
lib,
|
||||||
|
buildPythonPackage,
|
||||||
|
fetchPypi,
|
||||||
|
# deps
|
||||||
|
pbr,
|
||||||
|
pytest-asyncio,
|
||||||
|
pytestCheckHook,
|
||||||
|
pythonOlder,
|
||||||
|
setuptools-scm,
|
||||||
|
tornado,
|
||||||
|
typeguard,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
pname = "tenacity";
|
||||||
|
version = "8.2.3";
|
||||||
|
in
|
||||||
|
buildPythonPackage {
|
||||||
|
inherit pname version;
|
||||||
|
format = "pyproject";
|
||||||
|
|
||||||
|
disabled = pythonOlder "3.6";
|
||||||
|
|
||||||
|
src = fetchPypi {
|
||||||
|
inherit pname version;
|
||||||
|
hash = "sha256-U5jvDXjmP0AAfB+0wL/5bhkROU0vqNGU93YZwF/2zIo=";
|
||||||
|
};
|
||||||
|
|
||||||
|
nativeBuildInputs = [
|
||||||
|
pbr
|
||||||
|
setuptools-scm
|
||||||
|
];
|
||||||
|
|
||||||
|
nativeCheckInputs = [
|
||||||
|
pytest-asyncio
|
||||||
|
pytestCheckHook
|
||||||
|
tornado
|
||||||
|
typeguard
|
||||||
|
];
|
||||||
|
|
||||||
|
pythonImportsCheck = [pname];
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
homepage = "https://github.com/jd/tenacity";
|
||||||
|
description = "Retrying library for Python";
|
||||||
|
license = lib.licenses.asl20;
|
||||||
|
};
|
||||||
|
}
|
23
packages/kapowarr/typing-extensions/default.nix
Normal file
23
packages/kapowarr/typing-extensions/default.nix
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
# nix build inputs
|
||||||
|
buildPythonPackage,
|
||||||
|
fetchPypi,
|
||||||
|
# deps
|
||||||
|
flit-core,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
pname = "typing_extensions";
|
||||||
|
version = "4.12.2";
|
||||||
|
in
|
||||||
|
buildPythonPackage {
|
||||||
|
inherit pname version;
|
||||||
|
format = "pyproject";
|
||||||
|
|
||||||
|
build-system = [flit-core];
|
||||||
|
dependencies = [flit-core];
|
||||||
|
|
||||||
|
src = fetchPypi {
|
||||||
|
inherit pname version;
|
||||||
|
hash = "sha256-Gn6tVcflWd1N7ohW46iLQSJav+HOjfV7fBORX+Eh/7g=";
|
||||||
|
};
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue