db updates

This commit is contained in:
2025-09-09 08:50:21 -04:00
parent 9fcf5d8303
commit dd215d2f38
9 changed files with 908 additions and 74 deletions
-74
View File
@@ -1,74 +0,0 @@
# =================================
# NFOGuard - Simple Configuration
# =================================
# --- Required: Media Library Paths ---
# Container paths (what NFOGuard sees)
TV_PATHS=/media/tv,/media/tv6
MOVIE_PATHS=/media/movies,/media/movies6
# --- Required: Sonarr/Radarr Connection ---
SONARR_URL=http://sonarr:8989
SONARR_API_KEY=
RADARR_URL=http://radarr:7878
RADARR_API_KEY=
# --- Optional: Direct Radarr Database Access (High Performance) ---
# Enable direct database access for faster import date queries
# Supports both SQLite and PostgreSQL
RADARR_DB_TYPE=postgresql
# For PostgreSQL (recommended for production):
RADARR_DB_HOST=postgres_host
RADARR_DB_PORT=5432
RADARR_DB_NAME=radarr-main
RADARR_DB_USER=postgres
RADARR_DB_PASSWORD=your_password
# Alternative: use connection string
#RADARR_DB_URL=postgresql://user:pass@host:5432/dbname
# For SQLite (if using default Radarr setup):
#RADARR_DB_TYPE=sqlite
#RADARR_DB_PATH=/config/radarr.db
# --- Required: TMDB for Release Dates ---
# Get free API key from https://www.themoviedb.org/settings/api
TMDB_API_KEY=
TMDB_COUNTRY=US
# --- Behavior Settings ---
# Movie processing strategy: import_then_digital, digital_then_import
MOVIE_PRIORITY=import_then_digital
# When to query APIs: always, if_missing, never
MOVIE_POLL_MODE=always
# Update mode: backfill_only, overwrite
MOVIE_DATE_UPDATE_MODE=backfill_only
# Lock metadata in NFO files to prevent overwrites: true, false
LOCK_METADATA=true
# Brand name in NFO comments
MANAGER_BRAND=NFOGuard
# --- CRITICAL: Path Mapping ---
# What Radarr/Sonarr see vs what container sees
RADARR_ROOT_FOLDERS=/mnt/unionfs/Media/Movies/movies,/mnt/unionfs/Media/Movies/movies6
SONARR_ROOT_FOLDERS=/mnt/unionfs/Media/TV/tv,/mnt/unionfs/Media/TV/tv6
# Download path indicators (for nzbget, etc.)
DOWNLOAD_PATH_INDICATORS=/downloads/,/nzbget/,/sabnzbd/,/completed/,/torrents/
# --- Optional: Additional Digital Release Sources ---
#OMDB_API_KEY=your_omdb_api_key_here
JELLYSEERR_URL=http://jellyseerr:5055
JELLYSEERR_API_KEY=
# --- Optional: Advanced Settings ---
BATCH_DELAY=5.0
MAX_CONCURRENT_SERIES=3
TIMEOUT_SECONDS=45
DEBUG=false
DB_PATH=/app/data/media_dates.db
PORT=8080
+85
View File
@@ -0,0 +1,85 @@
# NFOGuard Environment Configuration Template
# Copy this to .env and customize for your setup
# ===========================================
# MEDIA PATHS (REQUIRED)
# ===========================================
# Paths where your movies and TV shows are stored inside the container
# Adjust these to match YOUR directory structure
TV_PATHS=/media/TV/tv,/media/TV/tv6
MOVIE_PATHS=/media/Movies/movies,/media/Movies/movies6
# ===========================================
# DATABASE CONFIGURATION
# ===========================================
# NFOGuard SQLite database location
DB_PATH=/app/data/media_dates.db
# ===========================================
# RADARR DATABASE CONNECTION (REQUIRED)
# ===========================================
# Connection to Radarr's PostgreSQL database
RADARR_DB_HOST=radarr-postgres
RADARR_DB_PORT=5432
RADARR_DB_NAME=radarr
RADARR_DB_USER=radarr
RADARR_DB_PASSWORD=your_radarr_db_password
# ===========================================
# RADARR API (OPTIONAL - for fallback)
# ===========================================
# Only needed if you want API fallback (not recommended for performance)
RADARR_URL=http://radarr:7878
RADARR_API_KEY=your_radarr_api_key
# ===========================================
# SONARR API (OPTIONAL)
# ===========================================
# Only needed for TV processing
SONARR_URL=http://sonarr:8989
SONARR_API_KEY=your_sonarr_api_key
# ===========================================
# NFO MANAGEMENT
# ===========================================
# Whether to create/update .nfo files
MANAGE_NFO=true
# Whether to fix file modification times to match import dates
FIX_DIR_MTIMES=true
# Whether to add <lockdata> tags to prevent metadata drift
LOCK_METADATA=true
# Brand name to add to NFO files
MANAGER_BRAND=NFOGuard
# ===========================================
# PROCESSING SETTINGS
# ===========================================
# Delay before processing batched webhook events (seconds)
BATCH_DELAY=5.0
# Maximum concurrent series processing
MAX_CONCURRENT_SERIES=3
# Movie date strategy: import_then_digital or digital_then_import
MOVIE_PRIORITY=import_then_digital
# When to query APIs: always, if_missing, never
MOVIE_POLL_MODE=always
# Update mode: backfill_only or overwrite
MOVIE_DATE_UPDATE_MODE=backfill_only
# ===========================================
# LOGGING
# ===========================================
# Enable debug logging
DEBUG=false
# ===========================================
# SERVER
# ===========================================
# Port to run the webhook server on
PORT=8080
+181
View File
@@ -0,0 +1,181 @@
# NFOGuard Deployment Guide
## 🚀 Quick Start for Docker Deployment
### Step 1: Environment Configuration
```bash
# Copy the environment template
cp .env.template .env
# Edit with your specific paths and database credentials
nano .env
```
**Key variables to customize in `.env`**:
```bash
# YOUR MEDIA PATHS (adjust these to your setup)
TV_PATHS=/media/TV/tv,/media/TV/tv6
MOVIE_PATHS=/media/Movies/movies,/media/Movies/movies6
HOST_MEDIA_PATH=/mnt/unionfs/Media
# YOUR RADARR DATABASE PASSWORD
RADARR_DB_PASSWORD=your_actual_password_here
```
### Step 2: Deploy with Docker Compose
```bash
# Start NFOGuard
docker-compose up -d
# Check logs
docker-compose logs -f nfoguard
```
### Step 3: Test Database Connection
```bash
# Test Radarr database connectivity
curl -X POST "http://localhost:8080/test/bulk-update"
# Expected response:
# {"status": "success", "movies_with_imdb": 1500, "database_type": "postgresql"}
```
### Step 4: Test Movie Discovery
```bash
# Test that your movie paths are correctly configured
curl -X POST "http://localhost:8080/test/movie-scan"
# Expected response:
# {"status": "success", "message": "Movie scan test found 1500 movies",
# "path_results": [{"path": "/media/Movies/movies", "exists": true, "movies_found": 800}, ...]}
```
### Step 5: Validate Database Performance
```bash
# Test the optimized database query performance
curl "http://localhost:8080/debug/movie/tt1674782"
# Expected response with July 2025 date:
# {"detected_import_date": "2025-07-08T03:30:04+00:00", "import_source": "radarr:history.import"}
```
## 📊 Production Workflow
### Manual Operations (via webhooks)
**1. Manual Movie Scan**
```bash
curl -X POST "http://localhost:8080/manual/scan?scan_type=movies"
```
**2. Bulk Update All Movies**
```bash
curl -X POST "http://localhost:8080/bulk/update"
```
**3. System Health Check**
```bash
curl "http://localhost:8080/health"
```
**4. Database Statistics**
```bash
curl "http://localhost:8080/stats"
```
**5. Debug Specific Movie**
```bash
curl "http://localhost:8080/debug/movie/tt1674782"
```
### Radarr Webhook Integration
**Add to Radarr → Settings → Connect → Webhook:**
- **Name**: NFOGuard
- **URL**: `http://nfoguard:8080/webhook/radarr`
- **Method**: POST
- **Events**: On Download, On Upgrade, On Rename
NFOGuard will automatically process movies when Radarr sends webhooks.
## 🔧 Environment Variables Reference
### Required Variables
| Variable | Description | Example |
|----------|-------------|---------|
| `MOVIE_PATHS` | Comma-separated movie directories | `/media/Movies/movies,/media/Movies/movies6` |
| `TV_PATHS` | Comma-separated TV directories | `/media/TV/tv,/media/TV/tv6` |
| `RADARR_DB_HOST` | Radarr PostgreSQL host | `radarr-postgres` |
| `RADARR_DB_PASSWORD` | Radarr database password | `your_password` |
### Optional Variables
| Variable | Default | Description |
|----------|---------|-------------|
| `HOST_MEDIA_PATH` | `/mnt/unionfs/Media` | Host path mounted to `/media` |
| `DB_PATH` | `/app/data/media_dates.db` | NFOGuard database location |
| `MANAGE_NFO` | `true` | Create/update .nfo files |
| `FIX_DIR_MTIMES` | `true` | Fix file modification times |
| `MOVIE_PRIORITY` | `import_then_digital` | Date preference strategy |
| `DEBUG` | `false` | Enable debug logging |
## 🏗 Docker Compose Customization
**For different media structures:**
```yaml
# Example: Different media structure
services:
nfoguard:
environment:
- TV_PATHS=/storage/tv_shows,/storage/anime
- MOVIE_PATHS=/storage/movies
volumes:
- "/storage:/storage:rw"
- "./data:/app/data"
```
**For external database networks:**
```yaml
# Example: Connect to existing Radarr network
services:
nfoguard:
networks:
- radarr_network
networks:
radarr_network:
external: true
```
## 🛠 Troubleshooting
### "0 movies processed"
1. Check paths: `curl -X POST "http://localhost:8080/test/movie-scan"`
2. Verify environment variables in `.env`
3. Ensure directories exist and have IMDb tags: `Movie Name [imdb-tt1234567] (2023)`
### Database connection errors
1. Test connection: `curl -X POST "http://localhost:8080/test/bulk-update"`
2. Verify `RADARR_DB_*` variables
3. Check Docker network connectivity
### Performance issues
1. Check health: `curl "http://localhost:8080/health"`
2. Monitor logs: `docker-compose logs -f nfoguard`
3. Verify database query performance: `curl "http://localhost:8080/debug/movie/tt1674782"`
## 📈 Monitoring
**Health Check Endpoint**: `GET /health`
- Server status and uptime
- Database connectivity
- Radarr database status
**Statistics Endpoint**: `GET /stats`
- Movie/TV counts
- Processing statistics
**Batch Queue Status**: `GET /batch/status`
- Pending webhook events
- Processing queue status
This deployment approach ensures NFOGuard can be easily configured for any media server setup while maintaining the database-only performance optimizations.
+131
View File
@@ -0,0 +1,131 @@
# NFOGuard Testing Guide
## 🧪 Test Scripts Overview
NFOGuard includes 3 specialized testing scripts to validate different parts of the workflow. These are designed to be run via webhooks or manual API calls, not directly on the command line.
### 1. `test_bulk_update.py` - Database Connection Validator
**Purpose**: Tests that the bulk update system can connect to databases without modifying any data.
**What it tests**:
- Radarr database connection
- NFOGuard database connection
- Query execution (reads first 5 movies)
- Import detection logic
**When to use**: Before running the full bulk update to ensure everything is configured correctly.
**How to run**:
```bash
# Via webhook/API inside container
curl -X POST "http://nfoguard:8080/test/bulk-update"
# Or manually inside container
python3 test_bulk_update.py
```
### 2. `test_movie_scan.py` - Directory Structure Validator
**Purpose**: Tests the movie directory scanning logic to ensure movies will be found.
**What it tests**:
- Path configuration validation
- IMDb ID parsing from directory names
- Movie discovery logic
- Directory structure understanding
**When to use**: When manual scans report "0 movies found" to debug path issues.
**Sample output**:
```
🔍 Testing Movie Directory Scanning
✅ '/media/Movies/movies' -> Found 150 movies with IMDb IDs
✅ 'The Dark Knight [imdb-tt0468569] (2008)' -> tt0468569
❌ 'Invalid Movie (2020)' -> No IMDb ID found
```
### 3. `test_end_to_end.py` - Complete Workflow Validator
**Purpose**: Tests the entire NFOGuard workflow from database queries to NFO creation.
**What it tests**:
- Server health and connectivity
- Database performance (your July 2025 date test)
- Manual scan trigger
- Batch processing status
- Statistics endpoints
**When to use**: After deployment to verify the complete system works end-to-end.
**How to run**:
```bash
# Via webhook inside container
curl -X POST "http://nfoguard:8080/test/end-to-end"
```
## 🚀 Testing Workflow for Docker Deployment
### Step 1: Deploy with Environment Variables
```bash
# Copy your environment template
cp .env.example .env
# Edit .env with your actual database password
nano .env
# Deploy
docker-compose up -d
```
### Step 2: Validate Database Connections
```bash
# Test database connectivity
curl -X POST "http://localhost:8080/test/bulk-update"
# Should show:
# ✅ Radarr database connection successful
# ✅ NFOGuard database connection successful
```
### Step 3: Test Movie Discovery
```bash
# Test that movies will be found
curl -X POST "http://localhost:8080/test/movie-scan"
# Should show paths and sample movies found
```
### Step 4: Run Full End-to-End Test
```bash
# Complete workflow test
curl -X POST "http://localhost:8080/test/end-to-end"
# Should show all systems operational
```
### Step 5: Production Testing
```bash
# Test database performance (your working July date)
curl "http://localhost:8080/debug/movie/tt1674782"
# Should return: 2025-07-08T03:30:04+00:00
# Run manual scan
curl -X POST "http://localhost:8080/manual/scan?scan_type=movies"
# Run bulk update
curl -X POST "http://localhost:8080/bulk/update"
```
## 🛠 Why These Tests Are Needed
1. **Docker Environment Isolation**: Tests run in the same environment as the production app
2. **Database-Only Validation**: Ensures the optimized database queries work correctly
3. **Path Configuration**: Validates that your specific directory structure is properly configured
4. **Webhook Integration**: Tests run via HTTP calls, same as Radarr webhooks
5. **CI/CD Integration**: Can be automated in deployment pipelines
## 🔍 Troubleshooting with Tests
**"0 movies processed"** → Run `test_movie_scan.py` to check path configuration
**Database errors** → Run `test_bulk_update.py` to validate connections
**Workflow issues** → Run `test_end_to_end.py` for comprehensive diagnosis
These tests are designed to catch issues before they impact your media processing workflow.
+77
View File
@@ -0,0 +1,77 @@
version: '3.8'
services:
nfoguard:
build: .
container_name: nfoguard
ports:
- "${PORT:-8080}:8080"
volumes:
# Mount your media directories (adjust these paths to match your setup)
- "${HOST_MEDIA_PATH:-/mnt/unionfs/Media}:/media:rw"
# NFOGuard data directory for database and logs
- "./data:/app/data"
# Optional: Mount config if you want to override
# - "./config:/app/config"
environment:
# Media paths inside container - customize these in your .env file
- TV_PATHS=${TV_PATHS:-/media/tv,/media/tv6}
- MOVIE_PATHS=${MOVIE_PATHS:-/media/movies,/media/movies6}
# Database
- DB_PATH=${DB_PATH:-/app/data/media_dates.db}
# Radarr Database (REQUIRED for database-only mode)
- RADARR_DB_HOST=${RADARR_DB_HOST}
- RADARR_DB_PORT=${RADARR_DB_PORT:-5432}
- RADARR_DB_NAME=${RADARR_DB_NAME:-radarr}
- RADARR_DB_USER=${RADARR_DB_USER}
- RADARR_DB_PASSWORD=${RADARR_DB_PASSWORD}
# Optional Radarr API (fallback only)
- RADARR_URL=${RADARR_URL:-}
- RADARR_API_KEY=${RADARR_API_KEY:-}
# Optional Sonarr API (for TV processing)
- SONARR_URL=${SONARR_URL:-}
- SONARR_API_KEY=${SONARR_API_KEY:-}
# NFO Management
- MANAGE_NFO=${MANAGE_NFO:-true}
- FIX_DIR_MTIMES=${FIX_DIR_MTIMES:-true}
- LOCK_METADATA=${LOCK_METADATA:-true}
- MANAGER_BRAND=${MANAGER_BRAND:-NFOGuard}
# Processing settings
- BATCH_DELAY=${BATCH_DELAY:-5.0}
- MAX_CONCURRENT_SERIES=${MAX_CONCURRENT_SERIES:-3}
- MOVIE_PRIORITY=${MOVIE_PRIORITY:-import_then_digital}
- MOVIE_POLL_MODE=${MOVIE_POLL_MODE:-always}
- MOVIE_DATE_UPDATE_MODE=${MOVIE_DATE_UPDATE_MODE:-backfill_only}
# Logging
- DEBUG=${DEBUG:-false}
# Server
- PORT=${PORT:-8080}
# Optional: Connect to Radarr's database network
# networks:
# - radarr_network
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
# Optional: If you need to connect to Radarr's database network
# networks:
# radarr_network:
# external: true
+69
View File
@@ -1044,6 +1044,75 @@ async def manual_scan(background_tasks: BackgroundTasks, path: Optional[str] = N
background_tasks.add_task(run_scan)
return {"status": "started", "message": f"Manual {scan_type} scan started"}
@app.post("/test/bulk-update")
async def test_bulk_update():
"""Test bulk update functionality without modifying data"""
try:
from clients.radarr_db_client import RadarrDbClient
# Test Radarr database
radarr_db = RadarrDbClient.from_env()
if not radarr_db:
return {"status": "error", "message": "Radarr database connection failed"}
# Test query execution
query = 'SELECT COUNT(*) FROM "Movies" m JOIN "MovieMetadata" mm ON m."MovieMetadataId" = mm."Id" WHERE mm."ImdbId" IS NOT NULL'
with radarr_db._get_connection() as conn:
cursor = conn.cursor()
cursor.execute(query)
movie_count = cursor.fetchone()[0]
return {
"status": "success",
"message": "Bulk update test passed",
"movies_with_imdb": movie_count,
"database_type": radarr_db.db_type
}
except Exception as e:
return {"status": "error", "message": f"Bulk update test failed: {e}"}
@app.post("/test/movie-scan")
async def test_movie_scan():
"""Test movie directory scanning logic"""
try:
results = []
for path in config.movie_paths:
path_result = {
"path": str(path),
"exists": path.exists(),
"movies_found": 0
}
if path.exists():
for item in path.iterdir():
if item.is_dir() and nfo_manager.parse_imdb_from_path(item):
path_result["movies_found"] += 1
results.append(path_result)
total_movies = sum(r["movies_found"] for r in results)
return {
"status": "success",
"message": f"Movie scan test found {total_movies} movies",
"path_results": results
}
except Exception as e:
return {"status": "error", "message": f"Movie scan test failed: {e}"}
@app.post("/bulk/update")
async def trigger_bulk_update(background_tasks: BackgroundTasks):
"""Trigger bulk update of all movies"""
async def run_bulk_update():
try:
from bulk_update_movies import bulk_update_all_movies
success = bulk_update_all_movies()
_log("INFO", f"Bulk update completed: {'success' if success else 'failed'}")
except Exception as e:
_log("ERROR", f"Bulk update error: {e}")
background_tasks.add_task(run_bulk_update)
return {"status": "started", "message": "Bulk update started"}
# ---------------------------
# Main
# ---------------------------
+99
View File
@@ -0,0 +1,99 @@
#!/usr/bin/env python3
"""
Test script for bulk_update_movies.py
This tests the bulk update functionality without modifying data
"""
import os
import sys
from pathlib import Path
def test_bulk_update_dry_run():
"""Test bulk update script in dry-run mode"""
print("🧪 Testing Bulk Update Script")
print("=" * 40)
# Check if we can import the required modules
try:
from clients.radarr_db_client import RadarrDbClient
from core.database import NFOGuardDatabase
print("✅ Successfully imported required modules")
except Exception as e:
print(f"❌ Import error: {e}")
return False
# Test database connections
print("\n🔌 Testing Database Connections...")
# Test Radarr database
try:
radarr_db = RadarrDbClient.from_env()
if not radarr_db:
print("❌ Radarr database connection failed - check environment variables")
return False
print("✅ Radarr database connection successful")
except Exception as e:
print(f"❌ Radarr database error: {e}")
return False
# Test NFOGuard database
try:
db_path = Path(os.environ.get("DB_PATH", "/app/data/media_dates.db"))
nfo_db = NFOGuardDatabase(db_path)
print(f"✅ NFOGuard database connection successful: {db_path}")
except Exception as e:
print(f"❌ NFOGuard database error: {e}")
return False
# Test query execution (dry run)
print("\n📊 Testing Query Execution...")
try:
query = """
SELECT
mm."ImdbId" as imdb_id,
m."Id" as movie_id,
mm."Title" as title,
mm."Year" as year,
m."Path" as path
FROM "Movies" m
JOIN "MovieMetadata" mm ON m."MovieMetadataId" = mm."Id"
WHERE mm."ImdbId" IS NOT NULL AND mm."ImdbId" != ''
ORDER BY mm."Title"
LIMIT 5
"""
with radarr_db._get_connection() as conn:
if radarr_db.db_type == "postgresql":
import psycopg2.extras
cursor = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
else:
cursor = conn.cursor()
cursor.execute(query)
movies = cursor.fetchall()
print(f"✅ Successfully queried Radarr database: {len(movies)} sample movies found")
# Show sample data
for i, movie in enumerate(movies):
if radarr_db.db_type == "postgresql":
imdb_id, title, year = movie['imdb_id'], movie['title'], movie['year']
else:
imdb_id, title, year = movie[0], movie[2], movie[3]
print(f" Sample {i+1}: {title} ({year}) - {imdb_id}")
except Exception as e:
print(f"❌ Query execution failed: {e}")
return False
print("\n✅ All tests passed! Bulk update script should work correctly.")
return True
if __name__ == "__main__":
success = test_bulk_update_dry_run()
if not success:
print("\n❌ Bulk update test failed!")
sys.exit(1)
else:
print("\n🎉 Bulk update test successful!")
+150
View File
@@ -0,0 +1,150 @@
#!/usr/bin/env python3
"""
End-to-end testing script for NFOGuard workflow
Tests the complete flow: Database -> Manual Scan -> NFO Creation
"""
import os
import sys
import requests
import time
from pathlib import Path
def test_server_health():
"""Test if the server is running and healthy"""
try:
response = requests.get("http://localhost:8080/health", timeout=10)
if response.status_code == 200:
health_data = response.json()
print(f"✅ Server is healthy: {health_data['status']}")
print(f" Version: {health_data['version']}")
print(f" Database: {health_data['database_status']}")
if health_data.get('radarr_database'):
radarr_status = health_data['radarr_database']['status']
print(f" Radarr DB: {radarr_status}")
return True
else:
print(f"❌ Server health check failed: {response.status_code}")
return False
except Exception as e:
print(f"❌ Cannot connect to server: {e}")
return False
def test_database_performance():
"""Test the database performance endpoint"""
try:
response = requests.get("http://localhost:8080/debug/movie/tt1674782", timeout=10)
if response.status_code == 200:
debug_data = response.json()
if debug_data.get('detected_import_date'):
print(f"✅ Database query works: {debug_data['detected_import_date']}")
print(f" Source: {debug_data['import_source']}")
return True
else:
print(f"❌ No import date found for test movie")
return False
else:
print(f"❌ Debug endpoint failed: {response.status_code}")
return False
except Exception as e:
print(f"❌ Database test failed: {e}")
return False
def test_manual_scan():
"""Test the manual scan functionality"""
try:
print("🔍 Starting manual movie scan...")
response = requests.post(
"http://localhost:8080/manual/scan?scan_type=movies",
timeout=30
)
if response.status_code == 200:
scan_data = response.json()
print(f"✅ Manual scan started: {scan_data['message']}")
# Wait a bit for processing
print("⏳ Waiting for scan to process...")
time.sleep(10)
# Check batch status
batch_response = requests.get("http://localhost:8080/batch/status", timeout=10)
if batch_response.status_code == 200:
batch_data = batch_response.json()
print(f" Pending items: {batch_data['pending_count']}")
print(f" Processing items: {batch_data['processing_count']}")
return True
else:
print(f"❌ Manual scan failed: {response.status_code}")
return False
except Exception as e:
print(f"❌ Manual scan test failed: {e}")
return False
def test_stats_endpoint():
"""Test database stats"""
try:
response = requests.get("http://localhost:8080/stats", timeout=10)
if response.status_code == 200:
stats = response.json()
print(f"✅ Database stats:")
print(f" Movies: {stats.get('movie_count', 0)}")
print(f" TV Series: {stats.get('series_count', 0)}")
print(f" Episodes: {stats.get('episode_count', 0)}")
return True
else:
print(f"❌ Stats endpoint failed: {response.status_code}")
return False
except Exception as e:
print(f"❌ Stats test failed: {e}")
return False
def run_end_to_end_test():
"""Run complete end-to-end test suite"""
print("🎯 NFOGuard End-to-End Testing")
print("=" * 50)
tests = [
("Server Health", test_server_health),
("Database Performance", test_database_performance),
("Manual Scan", test_manual_scan),
("Database Stats", test_stats_endpoint)
]
passed = 0
failed = 0
for test_name, test_func in tests:
print(f"\n🧪 Running: {test_name}")
try:
if test_func():
passed += 1
print(f"{test_name} passed")
else:
failed += 1
print(f"{test_name} failed")
except Exception as e:
failed += 1
print(f"{test_name} crashed: {e}")
print(f"\n📊 Test Results:")
print(f" ✅ Passed: {passed}")
print(f" ❌ Failed: {failed}")
print(f" 📈 Success Rate: {passed}/{passed+failed} ({100*passed/(passed+failed):.1f}%)")
return failed == 0
if __name__ == "__main__":
success = run_end_to_end_test()
if success:
print("\n🎉 All end-to-end tests passed!")
print("\n📋 Next Steps:")
print("1. Run bulk update: python3 bulk_update_movies.py")
print("2. Test with real movie: curl http://localhost:8080/debug/movie/tt1674782")
print("3. Check NFO file creation in /media/Movies/movies/")
print("4. Verify file timestamps match import dates")
else:
print("\n💥 Some tests failed - check the logs above")
sys.exit(1)
+116
View File
@@ -0,0 +1,116 @@
#!/usr/bin/env python3
"""
Test script to verify movie directory scanning logic
Simulates what the manual scan would do with correct paths
"""
import os
import sys
from pathlib import Path
def test_movie_scanning():
"""Test movie directory scanning logic"""
print("🔍 Testing Movie Directory Scanning")
print("=" * 50)
# Test paths - use the corrected paths from the code
movie_paths = [
Path("/media/Movies/movies"),
Path("/media/Movies/movies6")
]
print("📁 Testing paths:")
for path in movie_paths:
print(f" {path}")
# Import the NFO manager to test the IMDb parsing
try:
from core.nfo_manager import NFOManager
nfo_manager = NFOManager()
print("✅ Successfully imported NFOManager")
except Exception as e:
print(f"❌ Failed to import NFOManager: {e}")
return False
# Simulate the scanning logic
total_movies_found = 0
for media_path in movie_paths:
print(f"\n🎬 Scanning: {media_path}")
# Check if path exists (this will fail on your local machine but show the logic)
if not media_path.exists():
print(f" ⚠️ Path doesn't exist locally (expected on dev machine): {media_path}")
print(f" ️ On production server, this path should contain directories like:")
print(f" Example Movie [imdb-tt1234567] (2023)/")
print(f" Another Movie [imdb-tt7654321] (2022)/")
continue
movie_count = 0
for item in media_path.iterdir():
if item.is_dir():
imdb_id = nfo_manager.parse_imdb_from_path(item)
if imdb_id:
movie_count += 1
print(f" ✅ Found movie: {item.name} -> {imdb_id}")
else:
print(f" ⏭️ Skipped (no IMDb ID): {item.name}")
print(f" 📊 Found {movie_count} movies with IMDb IDs in {media_path}")
total_movies_found += movie_count
print(f"\n🎯 Total movies that would be processed: {total_movies_found}")
# Test IMDb ID parsing with sample directory names
print(f"\n🧪 Testing IMDb ID Parsing Logic:")
test_names = [
"The Dark Knight [imdb-tt0468569] (2008)",
"Inception [imdb-tt1375666] (2010)",
"Invalid Movie Name (2020)",
"Movie Without IMDb (2021)",
"Another Movie [imdb-tt1234567] (2023)"
]
for test_name in test_names:
test_path = Path(f"/fake/path/{test_name}")
imdb_id = nfo_manager.parse_imdb_from_path(test_path)
if imdb_id:
print(f"'{test_name}' -> {imdb_id}")
else:
print(f"'{test_name}' -> No IMDb ID found")
return True
def show_manual_scan_instructions():
"""Show instructions for testing on the production server"""
print("\n" + "="*60)
print("📋 NEXT STEPS - Test on Production Server")
print("="*60)
print()
print("1. 🔧 Update your environment variables:")
print(" export MOVIE_PATHS='/media/Movies/movies,/media/Movies/movies6'")
print(" export TV_PATHS='/media/TV/tv,/media/TV/tv6'")
print()
print("2. 🚀 Test the manual scan:")
print(" curl -X POST 'http://localhost:8080/manual/scan?scan_type=movies'")
print()
print("3. 📊 Check the logs for movie processing:")
print(" docker logs <container_name> | grep -E '(Processing movie|Completed movie scan)'")
print()
print("4. 🧪 Test the bulk update script:")
print(" python3 test_bulk_update.py")
print(" python3 bulk_update_movies.py")
print()
print("5. ✅ Verify end-to-end workflow:")
print(" curl http://localhost:8080/debug/movie/tt1674782")
print()
if __name__ == "__main__":
success = test_movie_scanning()
if success:
print("\n✅ Local testing completed successfully!")
show_manual_scan_instructions()
else:
print("\n❌ Local testing failed!")
sys.exit(1)