Refactor Nix package definition and enhance README for lidarr-mb-gap

- Updated `flake.nix` to import the new Nix package definition from `nix/package.nix`, streamlining the build process for the lidarr-mb-gap application.
- Enhanced the README.md to include new features such as NixOS module support for automated deployment, detailed deployment instructions, and configuration options for SSH and output directories.
- Added sections for troubleshooting output file issues and clarified the structure of the project, including new files for deployment and web serving.
This commit is contained in:
Danilo Reyes
2025-11-11 11:11:47 -06:00
parent e6f96107aa
commit a6d2e7f7df
5 changed files with 216 additions and 21 deletions

View File

@@ -13,6 +13,8 @@ A tool to identify missing albums on MusicBrainz from Deezer releases for artist
- 🎨 **Interactive HTML Report**: Filter by type (add/update) and by artist - 🎨 **Interactive HTML Report**: Filter by type (add/update) and by artist
- 🐍 **Python-based**: Clean, functional codebase with proper logging - 🐍 **Python-based**: Clean, functional codebase with proper logging
- ❄️ **Nix Support**: Fully packaged with Nix flake for reproducible builds - ❄️ **Nix Support**: Fully packaged with Nix flake for reproducible builds
- 🚀 **NixOS Module**: Automated deployment with systemd service and timer
- 🌐 **Web Serving**: Ready for deployment with Caddy or any web server
## Requirements ## Requirements
@@ -58,6 +60,7 @@ LIDARR_API_KEY=your-api-key-here
# Optional # Optional
SAMBL_URL=https://sambl.lioncat6.com SAMBL_URL=https://sambl.lioncat6.com
MAX_ARTISTS=5 # Limit number of artists processed (0 = no limit) MAX_ARTISTS=5 # Limit number of artists processed (0 = no limit)
OUTPUT_DIR=. # Directory where output files will be written (default: current directory)
``` ```
### Getting Your Lidarr API Key ### Getting Your Lidarr API Key
@@ -82,7 +85,7 @@ The script will:
1. Fetch all artists from Lidarr with `monitorNewItems` set to "new" or "all" 1. Fetch all artists from Lidarr with `monitorNewItems` set to "new" or "all"
2. For each artist, query SAMBL to find missing albums on MusicBrainz 2. For each artist, query SAMBL to find missing albums on MusicBrainz
3. Generate submission links (a-tisket and Harmony) 3. Generate submission links (a-tisket and Harmony)
4. Create two output files: 4. Create two output files in the directory specified by `OUTPUT_DIR` (or current directory):
- `missing_albums.json` - Machine-readable JSON report - `missing_albums.json` - Machine-readable JSON report
- `missing_albums.html` - Interactive HTML report with filters - `missing_albums.html` - Interactive HTML report with filters
@@ -110,7 +113,13 @@ Interactive HTML report with:
│ ├── main.py # Main application logic │ ├── main.py # Main application logic
│ ├── html_report.py # HTML report generation │ ├── html_report.py # HTML report generation
│ └── pyproject.toml # Python package configuration │ └── pyproject.toml # Python package configuration
├── nix/
│ └── package.nix # Shared Nix package definition
├── nixos/
│ ├── lidarr-mb-gap.nix # NixOS module for automated deployment
│ └── DEPLOYMENT.md # Detailed deployment guide
├── flake.nix # Nix flake definition ├── flake.nix # Nix flake definition
├── Caddyfile # Caddy configuration for serving reports
├── .env # Environment variables (create this) ├── .env # Environment variables (create this)
└── README.md └── README.md
``` ```
@@ -136,6 +145,40 @@ The application uses Python's logging module with systemd-friendly output:
Perfect for running as a systemd service. Perfect for running as a systemd service.
## Deployment
### NixOS Automated Deployment
This project includes a NixOS module for automated deployment with:
- Systemd service for report generation
- Systemd timer for periodic execution (configurable)
- Optional automatic rsync sync to VPS
- SSH key management for secure VPS access
- Caddy configuration for serving the HTML report
See [nixos/DEPLOYMENT.md](nixos/DEPLOYMENT.md) for detailed deployment instructions.
### Quick Start with NixOS
```nix
# In your NixOS configuration
services.lidarr-mb-gap = {
enable = true;
package = lidarr-mb-gap.packages.${system}.lidarr-mb-gap; # From flake
reportDir = "/var/lib/lidarr-mb-gap/reports";
envFile = "/var/lib/lidarr-mb-gap/.env";
runInterval = "daily";
# Optional: Auto-sync to VPS
syncToVPS = true;
vpsHost = "user@vps";
vpsPath = "/var/www/html";
sshKeyFile = "/var/lib/lidarr-mb-gap/.ssh/id_ed25519";
};
```
For complete setup instructions, including SSH key configuration and Caddy setup, see the [deployment guide](nixos/DEPLOYMENT.md).
## Example Output ## Example Output
``` ```
@@ -166,6 +209,11 @@ Perfect for running as a systemd service.
- Make sure you're running from the project root - Make sure you're running from the project root
- If using Nix, ensure the flake is properly built - If using Nix, ensure the flake is properly built
### Output files not appearing
- Check that `OUTPUT_DIR` environment variable points to a writable directory
- Ensure the directory exists and has proper permissions
- Check logs for any permission errors
## Contributing ## Contributing
1. Format code with `black src/` 1. Format code with `black src/`

View File

@@ -21,18 +21,9 @@
let let
pkgs = import nixpkgs { inherit system; }; pkgs = import nixpkgs { inherit system; };
lib = pkgs.lib; lib = pkgs.lib;
lidarr-mb-gap = pkgs.python3Packages.buildPythonApplication { lidarr-mb-gap = import ./nix/package.nix {
pname = "lidarr-mb-gap"; inherit pkgs lib;
version = "1.0.0";
src = lib.cleanSource ./src; src = lib.cleanSource ./src;
format = "pyproject";
nativeBuildInputs = with pkgs.python3Packages; [
setuptools
];
propagatedBuildInputs = with pkgs.python3Packages; [
requests
python-dotenv
];
}; };
in in
{ {

16
nix/package.nix Normal file
View File

@@ -0,0 +1,16 @@
{ pkgs, lib, src }:
pkgs.python3Packages.buildPythonApplication {
pname = "lidarr-mb-gap";
version = "1.0.0";
inherit src;
format = "pyproject";
nativeBuildInputs = with pkgs.python3Packages; [
setuptools
];
propagatedBuildInputs = with pkgs.python3Packages; [
requests
python-dotenv
];
}

View File

@@ -34,6 +34,13 @@ Add the module to your NixOS configuration. You have two options:
syncToVPS = true; syncToVPS = true;
vpsHost = "user@vps"; # Your SSH host alias vpsHost = "user@vps"; # Your SSH host alias
vpsPath = "/var/www/html"; vpsPath = "/var/www/html";
sshKeyFile = "/var/lib/lidarr-mb-gap/.ssh/id_ed25519";
sshKnownHosts = {
vps = {
hostNames = [ "vps" "vps.example.com" ];
publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI..."; # Get from ssh-keyscan
};
};
}; };
} }
``` ```
@@ -62,6 +69,18 @@ Add the module to your NixOS configuration. You have two options:
services.lidarr-mb-gap.reportDir = "/var/lib/lidarr-mb-gap/reports"; services.lidarr-mb-gap.reportDir = "/var/lib/lidarr-mb-gap/reports";
services.lidarr-mb-gap.envFile = "/var/lib/lidarr-mb-gap/.env"; services.lidarr-mb-gap.envFile = "/var/lib/lidarr-mb-gap/.env";
services.lidarr-mb-gap.runInterval = "daily"; services.lidarr-mb-gap.runInterval = "daily";
# Optional: SSH configuration for VPS sync
services.lidarr-mb-gap.syncToVPS = true;
services.lidarr-mb-gap.vpsHost = "user@vps";
services.lidarr-mb-gap.vpsPath = "/var/www/html";
services.lidarr-mb-gap.sshKeyFile = "/var/lib/lidarr-mb-gap/.ssh/id_ed25519";
services.lidarr-mb-gap.sshKnownHosts = {
vps = {
hostNames = [ "vps" "vps.example.com" ];
publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI...";
};
};
} }
./configuration.nix ./configuration.nix
]; ];
@@ -100,20 +119,96 @@ sudo chmod 600 /var/lib/lidarr-mb-gap/.env
### 3. Configure SSH for rsync (if using auto-sync) ### 3. Configure SSH for rsync (if using auto-sync)
If you enabled `syncToVPS`, set up SSH key authentication: If you enabled `syncToVPS`, you need to set up SSH key authentication for the `lidarr-mb-gap` user.
#### Step 1: Generate SSH Key Pair
```bash ```bash
# On the server # Generate a dedicated SSH key for the service
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_lidarr sudo -u lidarr-mb-gap ssh-keygen -t ed25519 -f /var/lib/lidarr-mb-gap/.ssh/id_ed25519 -N ""
ssh-copy-id -i ~/.ssh/id_ed25519_lidarr.pub user@vps
# Add to ~/.ssh/config # Or generate as your user and copy it
Host vps ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_lidarr -N ""
HostName your-vps-ip-or-domain sudo mkdir -p /var/lib/lidarr-mb-gap/.ssh
User your-username sudo cp ~/.ssh/id_ed25519_lidarr /var/lib/lidarr-mb-gap/.ssh/id_ed25519
IdentityFile ~/.ssh/id_ed25519_lidarr sudo cp ~/.ssh/id_ed25519_lidarr.pub /var/lib/lidarr-mb-gap/.ssh/id_ed25519.pub
sudo chown -R lidarr-mb-gap:lidarr-mb-gap /var/lib/lidarr-mb-gap/.ssh
sudo chmod 600 /var/lib/lidarr-mb-gap/.ssh/id_ed25519
sudo chmod 644 /var/lib/lidarr-mb-gap/.ssh/id_ed25519.pub
``` ```
#### Step 2: Add Public Key to VPS
```bash
# Copy the public key to your VPS
sudo -u lidarr-mb-gap cat /var/lib/lidarr-mb-gap/.ssh/id_ed25519.pub | ssh user@vps "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
# Or manually:
# 1. Display the public key:
sudo -u lidarr-mb-gap cat /var/lib/lidarr-mb-gap/.ssh/id_ed25519.pub
# 2. On your VPS, add it to ~/.ssh/authorized_keys (or the target user's authorized_keys)
```
#### Step 3: Get VPS Host Key (for known_hosts)
```bash
# Get the VPS host key fingerprint
ssh-keyscan -t ed25519 your-vps-hostname-or-ip
# This will output something like:
# your-vps-hostname ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI...
```
#### Step 4: Configure in NixOS
Add SSH configuration to your NixOS config:
```nix
services.lidarr-mb-gap = {
enable = true;
# ... other options ...
syncToVPS = true;
vpsHost = "user@vps-hostname"; # or "user@vps.example.com"
vpsPath = "/var/www/html";
# Path to SSH private key (optional, defaults to ~/.ssh/id_ed25519)
sshKeyFile = "/var/lib/lidarr-mb-gap/.ssh/id_ed25519";
# SSH known hosts (prevents host key verification prompts)
sshKnownHosts = {
vps = {
hostNames = [ "vps-hostname" "vps.example.com" "1.2.3.4" ]; # All possible hostnames/IPs
publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI..."; # From ssh-keyscan output
};
};
};
```
**Alternative: Manual Setup (if not using NixOS config)**
If you prefer to set up SSH keys manually without NixOS configuration:
```bash
# The service will use default SSH key location: /var/lib/lidarr-mb-gap/.ssh/id_ed25519
# Just ensure the key exists and is properly configured
```
#### Step 5: Test SSH Connection
Before enabling the service, test that SSH works:
```bash
# Test SSH connection as the service user
sudo -u lidarr-mb-gap ssh -i /var/lib/lidarr-mb-gap/.ssh/id_ed25519 user@vps "echo 'SSH connection successful'"
# Or if using default key location:
sudo -u lidarr-mb-gap ssh user@vps "echo 'SSH connection successful'"
```
If this works, rsync should work too. If you get host key verification errors, make sure you've configured `sshKnownHosts` in your NixOS config.
### 4. Build and Switch ### 4. Build and Switch
```bash ```bash

View File

@@ -3,6 +3,17 @@
let let
reportDir = "/var/lib/lidarr-mb-gap/reports"; reportDir = "/var/lib/lidarr-mb-gap/reports";
envFile = "/var/lib/lidarr-mb-gap/.env"; envFile = "/var/lib/lidarr-mb-gap/.env";
# Determine which package to use
lidarrMbGapPackage = if config.services.lidarr-mb-gap.package != null
then config.services.lidarr-mb-gap.package
else if config.services.lidarr-mb-gap.src != null
then import ../nix/package.nix {
inherit pkgs;
lib = pkgs.lib;
src = config.services.lidarr-mb-gap.src;
}
else throw "services.lidarr-mb-gap: Either 'package' or 'src' must be set.";
in in
{ {
options.services.lidarr-mb-gap = { options.services.lidarr-mb-gap = {
@@ -55,11 +66,35 @@ in
default = "/var/www/html"; default = "/var/www/html";
description = "Path on VPS where reports should be synced"; description = "Path on VPS where reports should be synced";
}; };
sshKeyFile = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "Path to SSH private key file for rsync. If null, uses default SSH key location.";
};
sshKnownHosts = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule {
options = {
hostNames = lib.mkOption {
type = lib.types.listOf lib.types.str;
description = "List of hostnames/IPs for this known host";
};
publicKey = lib.mkOption {
type = lib.types.str;
description = "SSH public key for the host";
};
};
});
default = {};
description = "SSH known hosts configuration for the VPS (same format as programs.ssh.knownHosts)";
};
}; };
config = lib.mkIf config.services.lidarr-mb-gap.enable { config = lib.mkIf config.services.lidarr-mb-gap.enable {
systemd.tmpfiles.rules = [ systemd.tmpfiles.rules = [
"d ${config.services.lidarr-mb-gap.reportDir} 0755 lidarr-mb-gap lidarr-mb-gap -" "d ${config.services.lidarr-mb-gap.reportDir} 0755 lidarr-mb-gap lidarr-mb-gap -"
"d /var/lib/lidarr-mb-gap/.ssh 0700 lidarr-mb-gap lidarr-mb-gap -"
]; ];
users.users.lidarr-mb-gap = { users.users.lidarr-mb-gap = {
@@ -71,6 +106,8 @@ in
users.groups.lidarr-mb-gap = {}; users.groups.lidarr-mb-gap = {};
programs.ssh.knownHosts = config.services.lidarr-mb-gap.sshKnownHosts;
systemd.services.lidarr-mb-gap = { systemd.services.lidarr-mb-gap = {
description = "Generate Lidarr MusicBrainz Gap Report"; description = "Generate Lidarr MusicBrainz Gap Report";
after = [ "network.target" ]; after = [ "network.target" ];
@@ -96,7 +133,15 @@ in
# Sync to VPS if enabled # Sync to VPS if enabled
${lib.optionalString (config.services.lidarr-mb-gap.syncToVPS && config.services.lidarr-mb-gap.vpsHost != null) '' ${lib.optionalString (config.services.lidarr-mb-gap.syncToVPS && config.services.lidarr-mb-gap.vpsHost != null) ''
# Set up SSH options
SSH_OPTS=""
${lib.optionalString (config.services.lidarr-mb-gap.sshKeyFile != null) ''
SSH_OPTS="-i ${config.services.lidarr-mb-gap.sshKeyFile}"
''}
# Use SSH options with rsync
${pkgs.rsync}/bin/rsync -avz --delete \ ${pkgs.rsync}/bin/rsync -avz --delete \
-e "ssh $SSH_OPTS -o StrictHostKeyChecking=yes" \
${config.services.lidarr-mb-gap.reportDir}/ \ ${config.services.lidarr-mb-gap.reportDir}/ \
${config.services.lidarr-mb-gap.vpsHost}:${config.services.lidarr-mb-gap.vpsPath}/ ${config.services.lidarr-mb-gap.vpsHost}:${config.services.lidarr-mb-gap.vpsPath}/
''} ''}