{ lib, stdenv, fetchFromGitHub, buildNpmPackage, python3, makeWrapper, ffmpeg, }: let pname = "bambuddy"; version = "1.2.5.7"; src = fetchFromGitHub { owner = "maziggy"; repo = "bambuddy"; rev = "188df76f8a7342542c0876dac68990ea2a8c8313"; # v1.2.5.7 hash = "sha256-KmlAdFoSIMa6Wahd4XPBvaBtpVR/5LPNMyaimuDZVb0="; }; # Runtime Python dependencies, mirroring upstream requirements.txt. # All of these ship in nixpkgs. Optional heavy extras (opencv4, # fast-simplification) are included for feature parity with the upstream # Docker image, which installs requirements.txt in full; the affected # features (plate detection, STL thumbnails) degrade gracefully if absent. pythonDeps = ps: with ps; [ # Web framework fastapi uvicorn uvloop httptools websockets python-dotenv # Database sqlalchemy aiosqlite asyncpg greenlet # Pydantic / settings pydantic pydantic-settings # Bambu Lab printer communication (MQTT / FTP) paho-mqtt aioftp pyftpdlib cryptography pyopenssl asyncssh # 3MF processing defusedxml # Excel export openpyxl # Utilities python-multipart aiofiles # QR codes / PDF generation / PDF thumbnails qrcode reportlab pypdfium2 # STL thumbnails trimesh matplotlib fast-simplification networkx lxml # System monitoring psutil # Authentication pyjwt passlib bcrypt ldap3 pyotp # HTTP clients idna httpx certifi curl-cffi urllib3 aiohttp # Plate detection opencv4 numpy pillow ]; pythonEnv = python3.withPackages pythonDeps; # Prebuilt React frontend. `vite build` emits to `../static` (the app root, # next to `backend/`), matching the upstream Dockerfile. frontend = buildNpmPackage { pname = "${pname}-web"; inherit version src; sourceRoot = "${src.name}/frontend"; npmDepsHash = "sha256-S+WU4jgs2DPWHHfspeo5k8vPECK+5SidGa8kzI4K4lw="; # The source tree arrives from the store read-only, but `vite build` # empties and writes ../static (the repo ships a committed static/ dir). preBuild = '' chmod -R u+w "$NIX_BUILD_TOP/${src.name}" rm -rf ../static ''; installPhase = '' runHook preInstall mkdir -p $out/share cp -r ../static $out/share/static runHook postInstall ''; meta = { description = "Web frontend for Bambuddy"; license = lib.licenses.agpl3Only; platforms = lib.platforms.unix; }; }; in stdenv.mkDerivation { inherit pname version src; dontBuild = true; nativeBuildInputs = [ makeWrapper ]; buildInputs = [ pythonEnv ]; passthru = { inherit pythonEnv frontend; }; installPhase = '' runHook preInstall # App root: `backend/` (Python sources) + `static/` (prebuilt frontend). # backend.app.core.config resolves both relative to this root, exactly # like the upstream Docker image (/app/backend + /app/static). mkdir -p $out/share/bambuddy cp -r ${src}/backend $out/share/bambuddy/backend cp -r ${frontend}/share/static $out/share/bambuddy/static chmod -R u+w $out/share/bambuddy # The upstream test suite is not shipped in the runtime package. rm -rf $out/share/bambuddy/backend/tests find $out/share/bambuddy -type d -name __pycache__ -prune -exec rm -rf {} + install -Dm644 ${src}/LICENSE -t $out/share/licenses/bambuddy mkdir -p $out/bin install -Dm755 ${./wrapper.sh} $out/bin/bambuddy # Substitute at build time so @out@ resolves to THIS package's path. # (A separate replaceVars derivation would substitute its own outPath # instead — which silently broke the PYTHONPATH in the launcher.) substituteInPlace $out/bin/bambuddy \ --replace-warn '@out@' "$out" \ --replace-warn '@pythonEnv@' "${pythonEnv}" # ffmpeg is used for timelapse conversion and camera stream re-encoding. wrapProgram $out/bin/bambuddy \ --prefix PATH : ${lib.makeBinPath [ ffmpeg ]} runHook postInstall ''; # Fix up the interpreter reference in the substituted wrapper. preFixup = '' patchShebangs $out/bin/bambuddy ''; meta = { description = "Self-hosted command center for Bambu Lab 3D printers"; longDescription = '' Bambuddy is a self-hosted command center for Bambu Lab 3D printers — from a single A1 to an entire print farm. Monitor printers in real time, archive every print automatically, slice and queue jobs locally, and manage the whole workflow without Bambu's cloud. This package bundles the FastAPI backend and the prebuilt React frontend behind a single `bambuddy` launcher. Configuration is done via environment variables (DATA_DIR, LOG_DIR, HOST, PORT, ...) — see the NixOS module (`services.bambuddy`) or upstream `.env.example` for the full list. ''; homepage = "https://bambuddy.cool/"; changelog = "https://github.com/maziggy/bambuddy/releases/tag/v${version}"; license = lib.licenses.agpl3Only; sourceProvenance = with lib.sourceTypes; [ fromSource ]; platforms = lib.platforms.unix; mainProgram = "bambuddy"; }; }