{ description = "NodeJS application with mpv, yt-dlp, and pulseaudio dependencies"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; flake-utils.url = "github:numtide/flake-utils"; }; outputs = { self, nixpkgs, flake-utils }: let # Define the NixOS module for the systemd service nixosModule = { config, lib, pkgs, ... }: let cfg = config.services.queuecube; in { options.services.queuecube = { enable = lib.mkEnableOption "QueueCube media player service"; port = lib.mkOption { type = lib.types.port; default = 3000; description = "Port on which QueueCube will listen"; }; enable_video = lib.mkOption { type = lib.types.bool; default = false; description = "Enable video playback"; }; store_path = lib.mkOption { type = lib.types.str; default = "/var/tmp/queuecube"; description = "Path to the store for QueueCube"; }; invidious = lib.mkOption { type = lib.types.submodule { options = { enable = lib.mkOption { type = lib.types.bool; default = false; description = "Enable Invidious"; }; url = lib.mkOption { type = lib.types.str; default = "http://invidious.nor"; description = "URL of the Invidious instance to use"; }; }; }; default = { enable = false; url = "http://invidious.nor"; }; }; user = lib.mkOption { type = lib.types.str; description = "User account under which QueueCube runs (required)"; }; }; config = lib.mkIf cfg.enable { users.users.${cfg.user} = { packages = [ self.packages.${pkgs.system}.queuecube ]; }; systemd.user.services.queuecube = { description = "QueueCube media player service"; wantedBy = [ "default.target" ]; after = [ "pipewire.service" "pipewire-pulse.service" ]; serviceConfig = { ExecStart = "${self.packages.${pkgs.system}.queuecube}/bin/queuecube"; Restart = "on-failure"; RestartSec = 5; # Allow access to X11 for mpv Environment = [ "DISPLAY=:0" ]; }; environment = { PORT = toString cfg.port; ENABLE_VIDEO = if cfg.enable_video then "1" else "0"; USE_INVIDIOUS = if cfg.invidious.enable then "1" else "0"; INVIDIOUS_BASE_URL = cfg.invidious.url; STORE_PATH = cfg.store_path; }; }; }; }; in flake-utils.lib.eachDefaultSystem (system: let pkgs = nixpkgs.legacyPackages.${system}; # Define the package using buildNpmPackage queuecube = pkgs.buildNpmPackage { pname = "queuecube"; version = "0.1.0"; src = ./.; # Skip the standard buildPhase and provide our own dontNpmBuild = true; buildPhase = '' # First install all dependencies npm install # Then run the build with workspaces flag npm run build --workspaces ''; # Runtime dependencies buildInputs = with pkgs; [ mpv yt-dlp pulseaudio ]; # Create a wrapper script to ensure runtime deps are available postInstall = '' # Create the necessary directories mkdir -p $out/lib/node_modules/queuecube # Copy the entire project with built files cp -r . $out/lib/node_modules/queuecube # Install the frontend build to the backend dist directory mkdir -p $out/lib/node_modules/queuecube/backend/dist/ cp -r frontend/dist $out/lib/node_modules/queuecube/backend/dist/frontend # Create bin directory if it doesn't exist mkdir -p $out/bin # Create executable script cat > $out/bin/queuecube <