shelfmark: init at 1.2.0, add NixOS module and test (#498942)
This commit is contained in:
@@ -957,6 +957,7 @@
|
||||
./services/misc/servarr/sonarr.nix
|
||||
./services/misc/servarr/whisparr.nix
|
||||
./services/misc/serviio.nix
|
||||
./services/misc/shelfmark.nix
|
||||
./services/misc/shoko.nix
|
||||
./services/misc/sickbeard.nix
|
||||
./services/misc/snapper.nix
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.services.shelfmark;
|
||||
in
|
||||
{
|
||||
options.services.shelfmark = {
|
||||
|
||||
enable = lib.mkEnableOption "Shelfmark, a self-hosted book and audiobook search and download interface";
|
||||
|
||||
package = lib.mkPackageOption pkgs "shelfmark" { };
|
||||
|
||||
openFirewall = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Open the appropriate ports in the firewall for Shelfmark.";
|
||||
};
|
||||
|
||||
environment = lib.mkOption {
|
||||
type = lib.types.submodule {
|
||||
freeformType = lib.types.attrsOf lib.types.str;
|
||||
options = {
|
||||
FLASK_HOST = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "127.0.0.1";
|
||||
example = "0.0.0.0";
|
||||
description = "The IP address to bind the Shelfmark server to.";
|
||||
};
|
||||
|
||||
FLASK_PORT = lib.mkOption {
|
||||
type = lib.types.port;
|
||||
default = 8084;
|
||||
apply = toString;
|
||||
description = "TCP port for the Shelfmark web interface.";
|
||||
};
|
||||
|
||||
ENABLE_LOGGING = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
apply = toString;
|
||||
default = false;
|
||||
description = "Whether to enable file logging. Disabled by default since systemd captures console output via journald.";
|
||||
};
|
||||
|
||||
CONFIG_DIR = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
default = "/var/lib/shelfmark";
|
||||
description = "Directory for Shelfmark configuration, database, and artwork cache.";
|
||||
};
|
||||
};
|
||||
};
|
||||
default = { };
|
||||
example = {
|
||||
SEARCH_MODE = "universal";
|
||||
LOG_LEVEL = "DEBUG";
|
||||
};
|
||||
description = ''
|
||||
Environment variables to pass to the Shelfmark service.
|
||||
See <https://github.com/calibrain/shelfmark/blob/main/docs/environment-variables.md>
|
||||
for available options.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
|
||||
systemd.services.shelfmark = {
|
||||
description = "Shelfmark - book and audiobook search and download interface";
|
||||
after = [ "network-online.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
inherit (cfg) environment;
|
||||
serviceConfig = {
|
||||
DynamicUser = true;
|
||||
ExecStart = "${lib.getExe cfg.package} -b ${cfg.environment.FLASK_HOST}:${cfg.environment.FLASK_PORT}";
|
||||
StateDirectory = "shelfmark";
|
||||
|
||||
ProtectSystem = "strict";
|
||||
ProtectHome = true;
|
||||
PrivateTmp = true;
|
||||
PrivateDevices = true;
|
||||
PrivateMounts = true;
|
||||
ProtectControlGroups = true;
|
||||
ProtectKernelTunables = true;
|
||||
RestrictSUIDSGID = true;
|
||||
RemoveIPC = true;
|
||||
UMask = "0077";
|
||||
|
||||
CapabilityBoundingSet = [ "" ];
|
||||
NoNewPrivileges = true;
|
||||
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelLogs = true;
|
||||
ProtectClock = true;
|
||||
SystemCallArchitectures = "native";
|
||||
SystemCallFilter = [
|
||||
"@system-service"
|
||||
"~@privileged"
|
||||
"~@resources"
|
||||
];
|
||||
|
||||
RestrictAddressFamilies = [
|
||||
"AF_INET"
|
||||
"AF_INET6"
|
||||
"AF_UNIX"
|
||||
];
|
||||
|
||||
PrivateUsers = true;
|
||||
|
||||
LockPersonality = true;
|
||||
ProtectHostname = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictNamespaces = true;
|
||||
ProtectProc = "invisible";
|
||||
ProcSubset = "pid";
|
||||
DeviceAllow = [ "" ];
|
||||
};
|
||||
};
|
||||
|
||||
networking.firewall = lib.mkIf cfg.openFirewall {
|
||||
allowedTCPPorts = [ (lib.toInt cfg.environment.FLASK_PORT) ];
|
||||
};
|
||||
};
|
||||
|
||||
meta = {
|
||||
maintainers = with lib.maintainers; [ jamiemagee ];
|
||||
};
|
||||
}
|
||||
@@ -1461,6 +1461,7 @@ in
|
||||
shadps4 = runTest ./shadps4.nix;
|
||||
sharkey = runTest ./web-apps/sharkey.nix;
|
||||
shattered-pixel-dungeon = runTest ./shattered-pixel-dungeon.nix;
|
||||
shelfmark = runTest ./shelfmark.nix;
|
||||
shiori = runTest ./shiori.nix;
|
||||
shoko = import ./shoko.nix { inherit runTest; };
|
||||
signal-desktop = runTest ./signal-desktop.nix;
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
{ lib, ... }:
|
||||
{
|
||||
name = "shelfmark";
|
||||
meta.maintainers = with lib.maintainers; [ jamiemagee ];
|
||||
|
||||
nodes.machine = {
|
||||
services.shelfmark = {
|
||||
enable = true;
|
||||
environment.FLASK_HOST = "0.0.0.0";
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
machine.wait_for_unit("shelfmark.service")
|
||||
machine.wait_for_open_port(8084)
|
||||
|
||||
with subtest("Health endpoint responds"):
|
||||
machine.succeed("curl --fail http://localhost:8084/api/health")
|
||||
'';
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
buildNpmPackage,
|
||||
shelfmark,
|
||||
}:
|
||||
|
||||
buildNpmPackage (finalAttrs: {
|
||||
pname = "shelfmark-frontend";
|
||||
inherit (shelfmark) version src;
|
||||
|
||||
sourceRoot = "${finalAttrs.src.name}/src/frontend";
|
||||
|
||||
npmDepsHash = "sha256-RAzotFGj0FGpfF7iyB5f2fdKFvMLcpJx142yplRwboU=";
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
cp -r dist $out
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
meta = {
|
||||
description = "Shelfmark frontend";
|
||||
homepage = "https://github.com/calibrain/shelfmark/tree/main/src/frontend";
|
||||
inherit (shelfmark.meta) changelog license maintainers;
|
||||
};
|
||||
})
|
||||
@@ -0,0 +1,96 @@
|
||||
{
|
||||
lib,
|
||||
stdenv,
|
||||
fetchFromGitHub,
|
||||
python3Packages,
|
||||
makeWrapper,
|
||||
nixosTests,
|
||||
shelfmark-frontend,
|
||||
unrar-free,
|
||||
}:
|
||||
|
||||
let
|
||||
pythonDeps = with python3Packages; [
|
||||
flask
|
||||
flask-cors
|
||||
flask-socketio
|
||||
python-socketio
|
||||
requests
|
||||
pysocks
|
||||
defusedxml
|
||||
beautifulsoup4
|
||||
tqdm
|
||||
dnspython
|
||||
gunicorn
|
||||
gevent
|
||||
gevent-websocket
|
||||
psutil
|
||||
emoji
|
||||
rarfile
|
||||
qbittorrent-api
|
||||
transmission-rpc
|
||||
authlib
|
||||
apprise
|
||||
];
|
||||
in
|
||||
stdenv.mkDerivation (finalAttrs: {
|
||||
pname = "shelfmark";
|
||||
version = "1.2.0";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "calibrain";
|
||||
repo = "shelfmark";
|
||||
tag = "v${finalAttrs.version}";
|
||||
hash = "sha256-t4t7je7Y/aezx/EX7paJIcsCq5qyZeU/+mPLeZ8oTPg=";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [
|
||||
python3Packages.wrapPython
|
||||
makeWrapper
|
||||
];
|
||||
|
||||
pythonPath = pythonDeps;
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
wrapPythonPrograms
|
||||
|
||||
mkdir -p $out/libexec $out/bin
|
||||
|
||||
cp -r shelfmark $out/libexec/shelfmark
|
||||
cp -r data $out/libexec/data
|
||||
ln -s ${finalAttrs.passthru.frontend} $out/libexec/frontend-dist
|
||||
|
||||
makeWrapper ${python3Packages.python.interpreter} $out/bin/shelfmark \
|
||||
--prefix PATH : ${
|
||||
lib.makeBinPath [
|
||||
python3Packages.python
|
||||
unrar-free
|
||||
]
|
||||
} \
|
||||
--set PYTHONPATH "$out/libexec:$program_PYTHONPATH" \
|
||||
--set USING_EXTERNAL_BYPASSER true \
|
||||
--add-flags "-m gunicorn.app.wsgiapp --worker-class geventwebsocket.gunicorn.workers.GeventWebSocketWorker --workers 1 -t 300 shelfmark.main:app"
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
passthru = {
|
||||
frontend = shelfmark-frontend.override {
|
||||
shelfmark = finalAttrs.finalPackage;
|
||||
};
|
||||
tests = {
|
||||
inherit (nixosTests) shelfmark;
|
||||
};
|
||||
};
|
||||
|
||||
meta = {
|
||||
description = "Self-hosted web interface for searching and downloading books and audiobooks";
|
||||
homepage = "https://github.com/calibrain/shelfmark";
|
||||
changelog = "https://github.com/calibrain/shelfmark/releases/tag/${finalAttrs.src.tag}";
|
||||
license = lib.licenses.mit;
|
||||
maintainers = [ lib.maintainers.jamiemagee ];
|
||||
mainProgram = "shelfmark";
|
||||
};
|
||||
})
|
||||
Reference in New Issue
Block a user