From 29ce0863ca655052c52465a5ee16590b8b95fc4f Mon Sep 17 00:00:00 2001 From: James Magahern Date: Sun, 2 Mar 2025 18:54:17 -0800 Subject: [PATCH] add nix flakes --- .gitignore | 1 + backend/src/server.ts | 5 +- flake.lock | 61 +++++++++++++ flake.nix | 201 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 266 insertions(+), 2 deletions(-) create mode 100644 flake.lock create mode 100644 flake.nix diff --git a/.gitignore b/.gitignore index 3dcd307..c738f51 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ build/ +result node_modules/ tsconfig.tsbuildinfo diff --git a/backend/src/server.ts b/backend/src/server.ts index 97fe728..d18a854 100644 --- a/backend/src/server.ts +++ b/backend/src/server.ts @@ -1,5 +1,6 @@ import express from "express"; import expressWs from "express-ws"; +import path from "path"; import { MediaPlayer } from "./MediaPlayer"; import { searchInvidious, fetchThumbnail } from "./InvidiousAPI"; import { PlaylistItem } from './types'; @@ -158,14 +159,14 @@ apiRouter.delete("/favorites", withErrorHandling(async (req, res) => { })); // Serve static files for React app (after building) -app.use(express.static("dist/frontend")); +app.use(express.static(path.join(__dirname, "../dist/frontend"))); // Mount API routes under /api app.use("/api", apiRouter); // Serve React app for all other routes (client-side routing) app.get("*", (req, res) => { - res.sendFile("dist/frontend/index.html", { root: "." }); + res.sendFile(path.join(__dirname, "../dist/frontend/index.html")); }); const port = process.env.PORT || 3000; diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..972ce4d --- /dev/null +++ b/flake.lock @@ -0,0 +1,61 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1740828860, + "narHash": "sha256-cjbHI+zUzK5CPsQZqMhE3npTyYFt9tJ3+ohcfaOF/WM=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "303bd8071377433a2d8f76e684ec773d70c5b642", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..41ee818 --- /dev/null +++ b/flake.nix @@ -0,0 +1,201 @@ +{ + 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"; + }; + + invidious = lib.mkOption { + type = lib.types.submodule { + options = { + enabled = 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"; + }; + }; + }; + }; + + user = lib.mkOption { + type = lib.types.str; + default = "queuecube"; + description = "User account under which QueueCube runs"; + }; + + group = lib.mkOption { + type = lib.types.str; + default = "queuecube"; + description = "Group under which QueueCube runs"; + }; + }; + + config = lib.mkIf cfg.enable { + users.users.${cfg.user} = lib.mkIf (cfg.user == "queuecube") { + isSystemUser = true; + group = cfg.group; + description = "QueueCube service user"; + home = "/var/lib/queuecube"; + createHome = true; + }; + + users.groups.${cfg.group} = lib.mkIf (cfg.group == "queuecube") {}; + + systemd.services.queuecube = { + description = "QueueCube media player service"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + + serviceConfig = { + ExecStart = "${self.packages.${pkgs.system}.queuecube}/bin/queuecube"; + Restart = "on-failure"; + User = cfg.user; + Group = cfg.group; + + # Audio/Video access + SupplementaryGroups = [ "audio" "video" ]; + + # 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.enabled then "1" else "0"; + INVIDIOUS_URL = cfg.invidious.url; + }; + }; + }; + }; + 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 <