Danilo Reyes 6cffbef8c6 fixes
2025-12-28 21:38:38 -06:00
2025-12-28 21:38:38 -06:00
2025-12-28 20:59:09 -06:00
2025-12-28 20:59:09 -06:00

Movie Map

A web application that visualizes the origin countries of your media collection from Radarr, Sonarr, and Lidarr, and tracks which foreign movies/shows you've watched.

Features

View 1: Collection Map

  • Visualizes all media in your *arr instances on a world map
  • Shows country of origin for each movie/show/artist
  • Color intensity indicates number of items per country
  • Filter by media type (movies, shows, music)
  • Pin markers show counts per country

View 2: Watched Map

  • Interactive map to track watched foreign movies and TV shows
  • Manually add watched items with country information
  • Add custom pins to mark countries
  • Visualize your personal "watched foreign media" journey

Architecture

  • Backend: FastAPI (Python) with PostgreSQL
  • Frontend: React + TypeScript + Vite + Leaflet
  • Database: PostgreSQL (via Unix socket)
  • Deployment: Nix flake with NixOS module

Development Setup

Prerequisites

  • Nix with flakes enabled
  • PostgreSQL running (accessible via socket)
  • Access to Radarr, Sonarr, Lidarr instances

Getting Started

  1. Enter the development shell:
nix develop
  1. Set up backend environment variables (create .env in backend/):
POSTGRES_SOCKET_PATH=/run/postgresql
POSTGRES_DB=jawz
POSTGRES_USER=jawz
SONARR_API_KEY=your_sonarr_api_key
RADARR_API_KEY=your_radarr_api_key
LIDARR_API_KEY=your_lidarr_api_key
PORT=8080
HOST=0.0.0.0  # Use 127.0.0.1 for localhost only
  1. (Optional) Set up frontend environment variables (create .env.local in frontend/):
# Only needed if backend port/host differs from defaults
VITE_BACKEND_HOST=127.0.0.1
VITE_BACKEND_PORT=8080
VITE_PORT=5173
  1. Start the backend (in one terminal):
cd backend
# Uses HOST and PORT from .env file (defaults to 0.0.0.0:8080)
python -m uvicorn main:app --reload --host ${HOST:-0.0.0.0} --port ${PORT:-8080}
  1. Start the frontend dev server (in another terminal):
cd frontend
npm install
# Optional: Set backend URL if different from default
# export VITE_BACKEND_HOST=127.0.0.1
# export VITE_BACKEND_PORT=8080
npm run dev
  1. Open http://localhost:5173 in your browser (or http://:5173 from another computer)

Development vs Production

Development Mode:

  • Backend runs on port 8080 (configurable)
  • Frontend dev server runs on port 5173 (configurable)
  • Frontend proxies API requests to backend
  • Both are accessible from other computers (bound to 0.0.0.0)

Production Mode (NixOS deployment):

  • Backend runs on configured port (default 8080)
  • Frontend is built and served as static files by the backend
  • No separate frontend server needed
  • Access via backend URL only

Note: The frontend dev server runs on port 5173 by default and proxies API requests to the backend. If you changed the backend port, set VITE_BACKEND_PORT environment variable to match. The frontend dev server binds to 0.0.0.0 by default, so it's accessible from other computers.

Building

Build the application using Nix:

nix build

This creates a combined package with both backend and frontend.

NixOS Deployment

1. Add the flake to your NixOS configuration

In your configuration.nix or a separate module:

{
  imports = [
    /path/to/movie-map/nixosModules.default
  ];

  services.moviemap = {
    enable = true;
    port = 8080;
    host = "0.0.0.0";  # Bind to all interfaces (use "127.0.0.1" for localhost only)
    postgresSocketPath = "/run/postgresql";
    # Secrets can be strings or file paths (for sops-nix integration)
    sonarrApiKey = "/run/secrets/sonarr-api-key";  # or "your_key_here"
    radarrApiKey = "/run/secrets/radarr-api-key";   # or "your_key_here"
    lidarrApiKey = "/run/secrets/lidarr-api-key";  # or "your_key_here"
    # Optional: admin token for sync endpoint
    adminToken = "/run/secrets/moviemap-admin-token";  # or "your_token_here"
  };
}

Or reference the flake directly:

{
  imports = [
    (builtins.getFlake "/path/to/movie-map").nixosModules.default
  ];
  
  services.moviemap = {
    enable = true;
    # ... configuration
  };
}

2. Run database migrations

Before starting the service, run migrations. You can do this either:

Option A: Run migrations manually before enabling the service

# SSH into your server
ssh server

# Enter the flake shell
cd /path/to/movie-map
nix develop

# Run migrations
cd backend
alembic upgrade head

Option B: Add a systemd service to run migrations on first start

You can add a one-shot systemd service that runs migrations before the main service starts. Add this to your NixOS configuration:

systemd.services.moviemap-migrate = {
  description = "Movie Map Database Migrations";
  serviceConfig = {
    Type = "oneshot";
    User = "moviemap";
    WorkingDirectory = "${appPackage}/backend";
    ExecStart = "${pythonEnv}/bin/alembic upgrade head";
  };
  before = [ "moviemap-backend.service" ];
  requiredBy = [ "moviemap-backend.service" ];
};

Or simply run migrations once manually, then enable the service.

3. Rebuild and enable

sudo nixos-rebuild switch

The service will be available at http://0.0.0.0:8080 (or your server's IP address). If you set host = "127.0.0.1", it will only be accessible from localhost (use a reverse proxy in that case).

Note: If you're accessing from another computer, make sure:

  1. The service is bound to 0.0.0.0 (default) or your server's IP address
  2. Your firewall allows incoming connections on the configured port
  3. If using NixOS, you may need to open the port in your firewall configuration:
    networking.firewall.allowedTCPPorts = [ 8080 ];
    

API Endpoints

Collection

  • GET /api/collection/summary?types=movie,show,music - Get collection summary by country

Watched Items

  • GET /api/watched - List all watched items
  • GET /api/watched/summary - Get watched summary by country
  • POST /api/watched - Create watched item
  • PATCH /api/watched/{id} - Update watched item
  • DELETE /api/watched/{id} - Delete watched item

Pins

  • GET /api/pins - List all manual pins
  • POST /api/pins - Create pin
  • DELETE /api/pins/{id} - Delete pin

Admin

  • POST /admin/sync - Trigger sync from all *arr instances (requires admin token if configured)

Database Schema

The application creates a moviemap schema in the jawz database with the following tables:

  • source - *arr instance configuration
  • media_item - Normalized media items from *arr
  • media_country - Country associations for media items
  • watched_item - User-tracked watched items
  • manual_pin - Custom pins on the map

Country Extraction

The sync process extracts country information from *arr metadata:

  • Radarr: Uses productionCountries from movie metadata
  • Sonarr: Uses originCountry from series metadata (if available)
  • Lidarr: Uses country field from artist metadata

If country information is not available, the item is stored without a country association (excluded from map visualization).

License

MIT

Description
No description provided
Readme 197 KiB
Languages
Python 55.8%
TypeScript 28.1%
Nix 6.3%
CSS 6.3%
Shell 2.9%
Other 0.6%