fixes: web interface and movie processing #54

Merged
sbcrumb merged 2 commits from dev into main 2025-10-20 10:27:38 -04:00
11 changed files with 418 additions and 184 deletions
+133 -19
View File
@@ -1,28 +1,142 @@
# NFOGuard Environment Variables
# ===========================================
# NFOGuard Configuration - CORRECTED VERSION
# ===========================================
# Main configuration file - safe to share for debugging
# Sensitive data (API keys, passwords) are in .env.secrets
# User and Group IDs
PUID=1000
PGID=1000
# ===========================================
# MEDIA PATHS (REQUIRED) - FIXED
# ===========================================
# Container paths (what NFOGuard sees inside container)
MOVIE_PATHS=/media/Movies/movies,/media/Movies/movies6
TV_PATHS=/media/TV/tv,/media/TV/tv6
# Timezone
TZ=UTC
# Radarr paths (what Radarr sees on the host system)
RADARR_ROOT_FOLDERS=/mnt/unionfs/Media/Movies/movies,/mnt/unionfs/Media/Movies/movies6
# Media path (for read-only access to scan NFO files)
MEDIA_PATH=/path/to/your/media
# Sonarr paths (what Sonarr sees on the host system) - FIXED VARIABLE NAME AND PATHS
SONARR_ROOT_FOLDERS=/mnt/unionfs/Media/TV/tv,/mnt/unionfs/Media/TV/tv6
# Database settings (if using PostgreSQL)
# DB_USER=nfoguard
# DB_PASSWORD=your_secure_password
# Download detection paths (for identifying downloads vs existing files)
DOWNLOAD_PATH_INDICATORS=/downloads/,/nzbget/,/completed/,/sabnzbd/,/torrents/
# Emby Plugin Deployment - Bind Mount Method (Recommended)
# Set this to the path where Emby plugins are installed on your host
# Common paths:
# - /var/lib/emby/plugins (native Emby install)
# - /path/to/emby/config/plugins (Docker Emby)
# - /config/plugins (linuxserver.io Emby)
EMBY_PLUGINS_PATH=/path/to/emby/plugins
# ===========================================
# DATABASE CONFIGURATION
# ===========================================
# NFOGuard Database Configuration (PostgreSQL - v2.6+)
# NOTE: For new installations, PostgreSQL is strongly recommended
# Set these values in .env.secrets for security:
# - DB_PASSWORD=your_secure_password
# - DB_USER=nfoguard (default)
# NFOGuard specific settings
# PostgreSQL Database Settings
DB_TYPE=postgresql
DB_HOST=nfoguard-db # Container name from docker-compose
DB_PORT=5432
DB_NAME=nfoguard
# Legacy SQLite Configuration (Deprecated in v2.6+)
# Only use for existing SQLite installations
# DB_PATH=/app/data/media_dates.db
# Log file directory
LOG_DIR=/app/data/logs
# ===========================================
# RADARR DATABASE CONNECTION (RECOMMENDED)
# ===========================================
# Direct database access for better performance
RADARR_DB_TYPE=postgresql
RADARR_DB_HOST=192.168.255.50
RADARR_DB_PORT=5432
RADARR_DB_NAME=radarr-main
RADARR_DB_USER=postgres
# ===========================================
# API CONNECTIONS (OPTIONAL)
# ===========================================
# API keys are stored in .env.secrets for security
RADARR_URL=http://radarr:7878
SONARR_URL=http://sonarr:8989
JELLYSEERR_URL=http://jellyseerr:5055
# ===========================================
# RELEASE DATE PROCESSING
# ===========================================
# Priority order for release date fallbacks (digital, physical, theatrical)
RELEASE_DATE_PRIORITY=digital,physical,theatrical
#RELEASE_DATE_PRIORITY=digital,theatrical,physical
ENABLE_SMART_DATE_VALIDATION=true
MAX_RELEASE_DATE_GAP_YEARS=10
# Prefer API release dates over file modification dates for manual imports
PREFER_RELEASE_DATES_OVER_FILE_DATES=true
# Disable file date fallback completely (recommended for clean imports)
ALLOW_FILE_DATE_FALLBACK=false
# TMDB country for regional release date preferences
TMDB_COUNTRY=US
# ===========================================
# NFO FILE MANAGEMENT
# ===========================================
# Create/update .nfo files
MANAGE_NFO=true
# Update file modification times to match import dates
FIX_DIR_MTIMES=true
# Add lockdata tags to prevent metadata overwrites
LOCK_METADATA=true
# Brand name in NFO comments
MANAGER_BRAND=NFOGuard
# ===========================================
# PROCESSING BEHAVIOR
# ===========================================
# Movie date update strategy
MOVIE_DATE_UPDATE_MODE=overwrite
MOVIE_PRESERVE_EXISTING=false
# When to update existing dates (always, missing_only, never)
UPDATE_MODE=always
# File modification time behavior (update, leave_alone)
MTIME_BEHAVIOR=update
# Manual scan priority: use existing NFO dates for speed vs check APIs for accuracy
# false (default) = Check external APIs first, use NFO as fallback (slower but accurate)
# true = Use NFO dates immediately without API checks (faster but may use wrong dates)
MANUAL_SCAN_PRIORITIZE_NFO=false
# ===========================================
# PERFORMANCE & BATCHING
# ===========================================
# Delay before processing batched events (seconds)
BATCH_DELAY=5.0
# Maximum concurrent series processing
MAX_CONCURRENT_SERIES=3
# API timeout in seconds
TIMEOUT_SECONDS=45
# ===========================================
# DEBUGGING
# ===========================================
# Enable verbose logging (true/false)
DEBUG=false
# Enable path mapping debug output (true/false)
PATH_DEBUG=false
# Suppress TVDB API warnings (true/false) - TVDB failures are common and non-critical
SUPPRESS_TVDB_WARNINGS=true
# ===========================================
# SERVER CONFIGURATION
# ===========================================
# Port for webhook server
PORT=8080
+10 -2
View File
@@ -4,9 +4,17 @@
# Add .env.secrets to your .gitignore
# ===========================================
# RADARR DATABASE CREDENTIALS
# NFOGUARD DATABASE CREDENTIALS (REQUIRED)
# ===========================================
# Database password for PostgreSQL connection
# NFOGuard PostgreSQL database password (REQUIRED for v2.6+)
DB_PASSWORD=your_secure_nfoguard_password
# Optional: Override default database user (defaults to 'nfoguard')
# DB_USER=nfoguard
# ===========================================
# RADARR DATABASE CREDENTIALS (OPTIONAL)
# ===========================================
# Database password for external Radarr PostgreSQL connection (optional optimization)
RADARR_DB_PASSWORD=your_radarr_db_password
# ===========================================
-129
View File
@@ -1,129 +0,0 @@
# ===========================================
# NFOGuard Configuration - CORRECTED VERSION
# ===========================================
# Main configuration file - safe to share for debugging
# Sensitive data (API keys, passwords) are in .env.secrets
# ===========================================
# MEDIA PATHS (REQUIRED) - FIXED
# ===========================================
# Container paths (what NFOGuard sees inside container)
MOVIE_PATHS=/media/Movies/movies,/media/Movies/movies6
TV_PATHS=/media/TV/tv,/media/TV/tv6
# Radarr paths (what Radarr sees on the host system)
RADARR_ROOT_FOLDERS=/mnt/unionfs/Media/Movies/movies,/mnt/unionfs/Media/Movies/movies6
# Sonarr paths (what Sonarr sees on the host system) - FIXED VARIABLE NAME AND PATHS
SONARR_ROOT_FOLDERS=/mnt/unionfs/Media/TV/tv,/mnt/unionfs/Media/TV/tv6
# Download detection paths (for identifying downloads vs existing files)
DOWNLOAD_PATH_INDICATORS=/downloads/,/nzbget/,/completed/,/sabnzbd/,/torrents/
# ===========================================
# DATABASE CONFIGURATION
# ===========================================
# NFOGuard SQLite database location
DB_PATH=/app/data/media_dates.db
# Log file directory
LOG_DIR=/app/data/logs
# ===========================================
# RADARR DATABASE CONNECTION (RECOMMENDED)
# ===========================================
# Direct database access for better performance
RADARR_DB_TYPE=postgresql
RADARR_DB_HOST=192.168.255.50
RADARR_DB_PORT=5432
RADARR_DB_NAME=radarr-main
RADARR_DB_USER=postgres
# ===========================================
# API CONNECTIONS (OPTIONAL)
# ===========================================
# API keys are stored in .env.secrets for security
RADARR_URL=http://radarr:7878
SONARR_URL=http://sonarr:8989
JELLYSEERR_URL=http://jellyseerr:5055
# ===========================================
# RELEASE DATE PROCESSING
# ===========================================
# Priority order for release date fallbacks (digital, physical, theatrical)
RELEASE_DATE_PRIORITY=digital,physical,theatrical
#RELEASE_DATE_PRIORITY=digital,theatrical,physical
ENABLE_SMART_DATE_VALIDATION=true
MAX_RELEASE_DATE_GAP_YEARS=10
# Prefer API release dates over file modification dates for manual imports
PREFER_RELEASE_DATES_OVER_FILE_DATES=true
# Disable file date fallback completely (recommended for clean imports)
ALLOW_FILE_DATE_FALLBACK=false
# TMDB country for regional release date preferences
TMDB_COUNTRY=US
# ===========================================
# NFO FILE MANAGEMENT
# ===========================================
# Create/update .nfo files
MANAGE_NFO=true
# Update file modification times to match import dates
FIX_DIR_MTIMES=true
# Add lockdata tags to prevent metadata overwrites
LOCK_METADATA=true
# Brand name in NFO comments
MANAGER_BRAND=NFOGuard
# ===========================================
# PROCESSING BEHAVIOR
# ===========================================
# Movie date update strategy
MOVIE_DATE_UPDATE_MODE=overwrite
MOVIE_PRESERVE_EXISTING=false
# When to update existing dates (always, missing_only, never)
UPDATE_MODE=always
# File modification time behavior (update, leave_alone)
MTIME_BEHAVIOR=update
# Manual scan priority: use existing NFO dates for speed vs check APIs for accuracy
# false (default) = Check external APIs first, use NFO as fallback (slower but accurate)
# true = Use NFO dates immediately without API checks (faster but may use wrong dates)
MANUAL_SCAN_PRIORITIZE_NFO=false
# ===========================================
# PERFORMANCE & BATCHING
# ===========================================
# Delay before processing batched events (seconds)
BATCH_DELAY=5.0
# Maximum concurrent series processing
MAX_CONCURRENT_SERIES=3
# API timeout in seconds
TIMEOUT_SECONDS=45
# ===========================================
# DEBUGGING
# ===========================================
# Enable verbose logging (true/false)
DEBUG=false
# Enable path mapping debug output (true/false)
PATH_DEBUG=false
# Suppress TVDB API warnings (true/false) - TVDB failures are common and non-critical
SUPPRESS_TVDB_WARNINGS=true
# ===========================================
# SERVER CONFIGURATION
# ===========================================
# Port for webhook server
PORT=8080
Binary file not shown.
+23 -22
View File
@@ -24,41 +24,42 @@
NFOGuard automatically updates movie and TV show NFO files with proper release dates and metadata when triggered by Radarr/Sonarr webhooks. It preserves existing metadata while adding clean, accurate date information at the bottom of NFO files.
## Features
## Features
### **🎬 Core Media Management**
### **Core Media Management**
- **Movie & TV Support** - Works with both Radarr and Sonarr
- **Smart Date Handling** - Prioritizes digital, physical, and theatrical release dates
- **Webhook Integration** - Triggers automatically on import, upgrade, and rename
- **NFO Preservation** - Maintains existing metadata, adds fields cleanly at bottom
- **Metadata Locking** - Prevents overwrites with lockdata tags
### **Performance & Scalability**
### **Performance & Scalability**
- **Async I/O Operations** - High-performance concurrent file processing
- **Batch Processing** - Efficient handling of multiple files simultaneously
- **Database Integration** - Direct PostgreSQL/SQLite access for better performance
- **Smart Concurrency** - Controlled parallel processing with rate limiting
- **PostgreSQL Database** - Production-ready database with optimized queries
- **Smart Skip Logic** - Database-first checking eliminates expensive filesystem scans
- **88% Scan Optimization** - TV library scans reduced from hours to minutes
### **🔧 Configuration & Validation**
### **Web Interface & Management**
- **Complete Web UI** - Episode and movie management with filtering and search
- **Database Cleanup Tools** - Delete orphaned episodes with confirmation dialogs
- **Real-time Statistics** - Live episode counts and source mapping
- **Manual Scan Control** - Smart, full, and incomplete scan modes
- **Health Monitoring** - System status and performance metrics
### **Configuration & Validation**
- **Comprehensive Config Validation** - Validates all settings before startup
- **Runtime Health Checks** - Monitors system health and dependencies
- **Path Validation** - Ensures media directories are accessible
- **Database Connectivity Tests** - Validates database connections
### **📊 Monitoring & Observability**
- **Health Check APIs** - `/api/v1/health`, `/api/v1/health/ready`, `/api/v1/health/live`
- **Prometheus Metrics** - `/api/v1/metrics` endpoint for monitoring integration
- **Performance Monitoring** - Operation timing, error rates, and bottleneck detection
- **Structured Logging** - JSON logs with correlation IDs for request tracing
- **System Status APIs** - Real-time performance and error metrics
### **🐳 Production Ready**
### **Production Ready**
- **Docker & Kubernetes** - Health checks for orchestration platforms
- **Grafana Compatible** - Metrics endpoints for dashboard integration
- **Graceful Shutdown** - Proper signal handling for container management
- **Configuration CLI** - Validation tools for troubleshooting
- **Modular Architecture** - Clean separation of concerns for maintainability
## 🚀 Quick Start
## Quick Start
### 1. Download Configuration Files
@@ -101,7 +102,7 @@ docker-compose logs -f nfoguard
curl http://localhost:8080/health
```
## ⚙️ Configuration
## Configuration
### Environment Files
@@ -134,7 +135,7 @@ DEBUG=false # Clean production logs
SUPPRESS_TVDB_WARNINGS=true # Hide non-critical API failures
```
## 🐳 Docker Images
## Docker Images
### Production (Stable)
```yaml
@@ -257,7 +258,7 @@ volumes:
- /home/user/media/tv:/media/TV/tv:rw
```
## 🔧 Troubleshooting
## Troubleshooting
### Check Logs
```bash
@@ -276,7 +277,7 @@ PATH_DEBUG=true
curl http://localhost:8080/health
```
## 📊 Monitoring & Observability
## Monitoring & Observability
NFOGuard provides comprehensive monitoring capabilities for production deployments:
@@ -356,7 +357,7 @@ LOG_LEVEL=INFO
3. **Webhooks**: Check URLs and ensure port 8080 is accessible
4. **Database**: Verify PostgreSQL credentials in `.env.secrets`
## 📊 What NFOGuard Does
## What NFOGuard Does
### Before
```xml
@@ -392,7 +393,7 @@ LOG_LEVEL=INFO
NFOGuard identifies movies and TV shows using two methods: directory names with IMDb IDs (primary) or NFO files with IMDb IDs (fallback). Your media should follow these conventions:
### 🎬 **Movies**
### **Movies**
**Directory Structure:**
```
+1 -1
View File
@@ -1 +1 @@
2.6.5
2.6.6
+61
View File
@@ -688,6 +688,9 @@ async def manual_scan(background_tasks: BackgroundTasks, path: Optional[str] = N
movie_skipped += 1
elif result == "processed":
movie_processed += 1
elif result == "no_video_files":
print(f"INFO: Skipped empty directory: {item.name}")
movie_skipped += 1
except Exception as e:
print(f"ERROR: Failed processing movie {item}: {e}")
movie_total += 1
@@ -1132,6 +1135,34 @@ async def delete_series_episodes(imdb_id: str, dependencies: dict):
}
async def delete_movie(imdb_id: str, dependencies: dict):
"""Delete a specific movie from the database"""
db = dependencies["db"]
try:
deleted = db.delete_movie(imdb_id)
if deleted:
return {
"success": True,
"message": f"Deleted movie {imdb_id} from database",
"imdb_id": imdb_id
}
else:
return {
"success": False,
"message": f"Movie {imdb_id} not found in database",
"imdb_id": imdb_id
}
except Exception as e:
return {
"success": False,
"error": str(e),
"imdb_id": imdb_id
}
async def cleanup_orphaned_episodes(dependencies: dict):
"""Find and delete episodes that don't have corresponding video files"""
db = dependencies["db"]
@@ -1154,6 +1185,28 @@ async def cleanup_orphaned_episodes(dependencies: dict):
}
async def cleanup_orphaned_movies(dependencies: dict):
"""Find and delete movies that don't have corresponding video files"""
db = dependencies["db"]
try:
deleted_movies = db.delete_orphaned_movies()
return {
"success": True,
"message": f"Cleaned up {len(deleted_movies)} orphaned movies",
"deleted_count": len(deleted_movies),
"deleted_movies": deleted_movies
}
except Exception as e:
return {
"success": False,
"error": str(e),
"message": "Failed to cleanup orphaned movies"
}
# ---------------------------
# Route Registration
# ---------------------------
@@ -1212,10 +1265,18 @@ def register_routes(app, dependencies: dict):
async def _delete_series_episodes(imdb_id: str):
return await delete_series_episodes(imdb_id, dependencies)
@app.delete("/database/movie/{imdb_id}")
async def _delete_movie(imdb_id: str):
return await delete_movie(imdb_id, dependencies)
@app.post("/database/cleanup/orphaned-episodes")
async def _cleanup_orphaned_episodes():
return await cleanup_orphaned_episodes(dependencies)
@app.post("/database/cleanup/orphaned-movies")
async def _cleanup_orphaned_movies():
return await cleanup_orphaned_movies(dependencies)
@app.post("/manual/scan")
async def _manual_scan(background_tasks: BackgroundTasks, path: Optional[str] = None, scan_type: str = "both", scan_mode: str = "smart"):
return await manual_scan(background_tasks, path, scan_type, scan_mode, dependencies)
+91 -1
View File
@@ -205,7 +205,7 @@ class NFOGuardDatabase:
# Debug: Check what was actually saved
cursor.execute("SELECT dateadded, source FROM movies WHERE imdb_id = %s", (imdb_id,))
result = cursor.fetchone()
print(f"🔍 DATABASE VERIFY: After upsert, found dateadded={result[0] if result else 'NOT_FOUND'}, source={result[1] if result else 'NOT_FOUND'}")
print(f"🔍 DATABASE VERIFY: After upsert, found dateadded={result['dateadded'] if result else 'NOT_FOUND'}, source={result['source'] if result else 'NOT_FOUND'}")
def get_series_episodes(self, imdb_id: str, has_video_file_only: bool = False) -> List[Dict]:
"""Get all episodes for a series"""
@@ -411,6 +411,96 @@ class NFOGuardDatabase:
return deleted_episodes
def delete_movie(self, imdb_id: str) -> bool:
"""
Delete a specific movie from the database
Args:
imdb_id: Movie IMDb ID
Returns:
True if movie was deleted, False if not found
"""
with self.get_connection() as conn:
cursor = conn.cursor()
cursor.execute("""
DELETE FROM movies
WHERE imdb_id = %s
""", (imdb_id,))
deleted_count = cursor.rowcount
conn.commit()
return deleted_count > 0
def delete_orphaned_movies(self) -> List[Dict]:
"""
Find and delete movies that don't have corresponding video files on disk
This requires checking filesystem for each movie, so use carefully
Returns:
List of deleted movies with their details
"""
from pathlib import Path
deleted_movies = []
with self.get_connection() as conn:
cursor = conn.cursor()
# Get all movies with their paths
cursor.execute("""
SELECT imdb_id, path, dateadded, source
FROM movies
""")
movies_list = cursor.fetchall()
for movie in movies_list:
imdb_id = movie['imdb_id']
movie_path = Path(movie['path'])
if not movie_path.exists():
# Movie directory doesn't exist - delete it
cursor.execute("""
DELETE FROM movies
WHERE imdb_id = %s
""", (imdb_id,))
deleted_movies.append({
'imdb_id': imdb_id,
'reason': 'directory_not_found',
'path': str(movie_path),
'dateadded': movie['dateadded'],
'source': movie['source']
})
continue
# Check for video files
video_exts = (".mkv", ".mp4", ".avi", ".mov", ".m4v")
has_video = any(f.is_file() and f.suffix.lower() in video_exts
for f in movie_path.iterdir() if f.is_file())
if not has_video:
# No video files found - delete this movie
cursor.execute("""
DELETE FROM movies
WHERE imdb_id = %s
""", (imdb_id,))
deleted_movies.append({
'imdb_id': imdb_id,
'reason': 'no_video_files',
'path': str(movie_path),
'dateadded': movie['dateadded'],
'source': movie['source']
})
conn.commit()
return deleted_movies
def close(self):
"""Close all database connections"""
if hasattr(self._local, 'connection'):
+59 -6
View File
@@ -6,13 +6,17 @@ services:
image: sbcrumb/nfoguard:latest
# Alternative: Use specific version
# image: sbcrumb/nfoguard:v1.5.5
# image: sbcrumb/nfoguard:v2.6.5
# Alternative: Use development version
# image: sbcrumb/nfoguard:dev
container_name: nfoguard
# Database dependency
depends_on:
- nfoguard-postgres
# Restart policy
restart: unless-stopped
@@ -87,6 +91,54 @@ services:
max-size: "10m"
max-file: "3"
# PostgreSQL Database (Required for v2.6+)
nfoguard-postgres:
image: postgres:15-alpine
container_name: nfoguard-db
# Restart policy
restart: unless-stopped
# Environment variables for PostgreSQL
environment:
- POSTGRES_DB=nfoguard
- POSTGRES_USER=nfoguard
- POSTGRES_PASSWORD=${DB_PASSWORD} # Set in .env.secrets
- POSTGRES_INITDB_ARGS=--encoding=UTF-8 --lc-collate=C --lc-ctype=C
# PostgreSQL data persistence
volumes:
- ./postgres-data:/var/lib/postgresql/data
# PostgreSQL port (optional - only needed for external access)
# ports:
# - "5432:5432"
# Health check for database
healthcheck:
test: ["CMD-SHELL", "pg_isready -U nfoguard -d nfoguard"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
# Resource limits for database
deploy:
resources:
limits:
memory: 256M
cpus: '0.3'
reservations:
memory: 128M
cpus: '0.1'
# Logging configuration
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# Optional: Custom network for media services
# networks:
# media-network:
@@ -97,12 +149,13 @@ services:
# ===========================================
# 1. Copy this file to docker-compose.yml
# 2. Update volume mounts to match your actual media paths
# 3. Copy .env.template to .env and configure
# 4. Copy .env.secrets.template to .env.secrets and add credentials
# 5. Create data directory: mkdir -p ./data
# 3. Copy .env.example to .env and configure all settings
# 4. Copy .env.secrets.example to .env.secrets and add credentials (especially DB_PASSWORD)
# 5. Create directories: mkdir -p ./data ./postgres-data
# 6. Run: docker-compose up -d
# 7. Check logs: docker-compose logs -f nfoguard
# 8. Access health check: curl http://localhost:8080/health
# 7. Check logs: docker-compose logs -f
# 8. Access web interface: http://localhost:8080
# 9. Access health check: curl http://localhost:8080/health
# ===========================================
# VOLUME MAPPING EXAMPLES
+2 -3
View File
@@ -188,9 +188,8 @@ class MovieProcessor:
has_video = any(f.is_file() and f.suffix.lower() in video_exts for f in movie_path.iterdir())
if not has_video:
_log("WARNING", f"No video files found in: {movie_path}")
self.db.upsert_movie_dates(imdb_id, None, None, None, False)
return "processed"
_log("WARNING", f"No video files found in: {movie_path} - skipping database entry")
return "no_video_files"
# TIER 1: Check database first (fastest - local lookup)
existing = self.db.get_movie_dates(imdb_id)
+37
View File
@@ -289,6 +289,9 @@ function updateMoviesTable(data) {
<button class="btn btn-sm btn-secondary" onclick="debugMovie('${movie.imdb_id}')" title="Debug Data">
<i class="fas fa-bug"></i>
</button>
<button class="btn btn-sm btn-danger" onclick="deleteMovie('${movie.imdb_id}')" style="margin-left: 5px;" title="Delete Movie">
<i class="fas fa-trash"></i> Delete
</button>
</td>
</tr>
`;
@@ -1315,6 +1318,40 @@ async function deleteEpisode(imdbId, season, episode) {
}
}
// Movie deletion functionality
async function deleteMovie(imdbId) {
// Confirmation dialog
if (!confirm(`⚠️ Delete Movie?\n\nThis will permanently remove the movie (${imdbId}) from the database.\n\nAre you sure you want to continue?`)) {
return;
}
try {
const response = await fetch(`/database/movie/${imdbId}`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
}
});
const result = await response.json();
if (response.ok && result.success) {
showToast(`✅ Movie deleted successfully`, 'success');
// Refresh the movies table
loadMovies(currentMoviesPage);
} else {
const errorMsg = result.message || result.error || 'Unknown error';
showToast(`❌ Failed to delete movie: ${errorMsg}`, 'error');
}
} catch (error) {
console.error('Delete movie failed:', error);
showToast(`❌ Delete failed: ${error.message}`, 'error');
}
}
// Update episode counts in modal after deletion
function updateEpisodeModalCounts() {
const remainingRows = document.querySelectorAll('#episodes-table-body tr');