Files
media-map/flake.nix
Danilo Reyes 1329958b4e
Some checks failed
Test Suite / test (push) Failing after 45s
Add NixOS VM configuration and new media search endpoint
- Introduced a new NixOS VM configuration in `flake.nix` for testing purposes.
- Updated CI workflow to build the VM using the flake input for a more streamlined process.
- Added a new API endpoint `/search` in the collection API to search owned media by title, with optional filtering by media type.
- Refactored frontend components to utilize the new media search functionality, updating types and state management accordingly.
- Enhanced CSS for the map component to ensure proper rendering in various layouts.
2025-12-28 23:02:48 -06:00

207 lines
6.7 KiB
Nix

{
description = "Movie Map - Visualize media origin countries from Radarr/Sonarr/Lidarr";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
};
outputs = { self, nixpkgs }:
let
system = "x86_64-linux";
pkgs = import nixpkgs { inherit system; };
# Python dependencies
pythonEnv = pkgs.python3.withPackages (ps: with ps; [
fastapi
uvicorn
psycopg
psycopg-pool
alembic
sqlalchemy
httpx
pydantic
pydantic-settings
python-multipart
]);
# Node.js for frontend
nodejs = pkgs.nodejs_20;
# Frontend build
frontend = pkgs.buildNpmPackage {
name = "moviemap-frontend";
src = ./frontend;
npmDepsHash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; # Update after first build
buildPhase = ''
npm run build
'';
installPhase = ''
mkdir -p $out
cp -r dist/* $out/
'';
};
# Backend package
backend = pkgs.stdenv.mkDerivation {
name = "moviemap-backend";
src = ./backend;
buildInputs = [ pythonEnv ];
installPhase = ''
mkdir -p $out/backend
cp -r . $out/backend/
chmod +x $out/backend/run.sh
# Make Python scripts executable
find $out/backend -name "*.py" -exec chmod +x {} \;
'';
};
# Combined package
app = pkgs.stdenv.mkDerivation {
name = "moviemap";
buildInputs = [ backend frontend ];
buildPhase = "true";
installPhase = ''
mkdir -p $out/backend
cp -r ${backend}/backend/* $out/backend/
# Copy frontend dist to backend for serving
mkdir -p $out/backend/frontend/dist
cp -r ${frontend}/* $out/backend/frontend/dist/
'';
};
in
{
packages.${system} = {
default = app;
backend = backend;
frontend = frontend;
};
nixosConfigurations.test-vm = nixpkgs.lib.nixosSystem {
inherit system;
modules = [
./nix/test-vm.nix
];
};
devShells.${system}.default = pkgs.mkShell {
buildInputs = [
pythonEnv
nodejs
pkgs.nodePackages.npm
pkgs.postgresql
pkgs.alejandra # Nix formatter
];
shellHook = ''
echo "Movie Map development environment"
echo "Python: $(python --version)"
echo "Node: $(node --version)"
'';
};
nixosModules.default = { config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.moviemap;
appPackage = self.packages.x86_64-linux.default;
# Check if a value is a file path (starts with /)
isPath = v: lib.hasPrefix "/" (toString v);
# Build environment variables - use file paths directly for secrets
# The run.sh script will read from files at runtime
envVars = [
"PORT=${toString cfg.port}"
"HOST=${cfg.host}"
"POSTGRES_SOCKET_PATH=${cfg.postgresSocketPath}"
] ++ [
# API keys - if path, pass as-is; if string, pass directly
(if isPath cfg.sonarrApiKey
then "SONARR_API_KEY_FILE=${toString cfg.sonarrApiKey}"
else "SONARR_API_KEY=${toString cfg.sonarrApiKey}")
(if isPath cfg.radarrApiKey
then "RADARR_API_KEY_FILE=${toString cfg.radarrApiKey}"
else "RADARR_API_KEY=${toString cfg.radarrApiKey}")
(if isPath cfg.lidarrApiKey
then "LIDARR_API_KEY_FILE=${toString cfg.lidarrApiKey}"
else "LIDARR_API_KEY=${toString cfg.lidarrApiKey}")
] ++ lib.optional (cfg.adminToken != null)
(if isPath cfg.adminToken
then "MOVIEMAP_ADMIN_TOKEN_FILE=${toString cfg.adminToken}"
else "MOVIEMAP_ADMIN_TOKEN=${toString cfg.adminToken}");
in
{
options.services.moviemap = {
enable = mkEnableOption "Movie Map service";
port = mkOption {
type = types.int;
default = 8080;
description = "Port to bind the backend server";
};
host = mkOption {
type = types.str;
default = "0.0.0.0";
description = "Host address to bind the server (0.0.0.0 for all interfaces, 127.0.0.1 for localhost only)";
};
postgresSocketPath = mkOption {
type = types.str;
default = "/run/postgresql";
description = "PostgreSQL socket directory";
};
sonarrApiKey = mkOption {
type = types.either types.str types.path;
description = "Sonarr API key (string or path to file, e.g., /run/secrets/sonarr-api-key)";
};
radarrApiKey = mkOption {
type = types.either types.str types.path;
description = "Radarr API key (string or path to file, e.g., /run/secrets/radarr-api-key)";
};
lidarrApiKey = mkOption {
type = types.either types.str types.path;
description = "Lidarr API key (string or path to file, e.g., /run/secrets/lidarr-api-key)";
};
adminToken = mkOption {
type = types.nullOr (types.either types.str types.path);
default = null;
description = "Optional admin token for sync endpoint (string or path to file)";
};
};
config = mkIf cfg.enable {
systemd.services.moviemap-backend = {
description = "Movie Map Backend";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" "postgresql.service" ];
serviceConfig = {
Type = "simple";
ExecStart = "${appPackage}/backend/run.sh";
Restart = "always";
RestartSec = "10s";
Environment = envVars;
User = "moviemap";
Group = "moviemap";
};
};
users.users.moviemap = {
isSystemUser = true;
group = "moviemap";
description = "Movie Map service user";
};
users.groups.moviemap = {};
};
};
};
}