diff --git a/api/web_routes.py b/api/web_routes.py index 68908fc..4a81434 100644 --- a/api/web_routes.py +++ b/api/web_routes.py @@ -1538,46 +1538,76 @@ async def execute_database_query(dependencies: dict, query: str, limit: int = 10 async def get_episodes_missing_nfo_dateadded(dependencies: dict): - """Find episodes that have dateadded in database but missing from NFO files""" + """Find episodes and movies that have dateadded in database but missing from NFO files""" db = dependencies["db"] config = dependencies["config"] try: - # Get all episodes with dateadded in database + # Get all episodes with video files (even if dateadded is NULL, we can check if they should have dates) with db.get_connection() as conn: cursor = conn.cursor() cursor.execute(""" SELECT e.imdb_id, e.season, e.episode, e.dateadded, e.source, e.has_video_file, - s.path as series_path + s.path as series_path, 'episode' as media_type FROM episodes e JOIN series s ON e.imdb_id = s.imdb_id - WHERE e.dateadded IS NOT NULL - AND e.has_video_file = TRUE + WHERE e.has_video_file = TRUE ORDER BY e.imdb_id, e.season, e.episode - LIMIT 500 + LIMIT 2000 """) episodes = [dict(row) for row in cursor.fetchall()] + + # Also get movies with video files + cursor.execute(""" + SELECT m.imdb_id, NULL as season, NULL as episode, m.dateadded, m.source, m.has_video_file, + m.path as series_path, 'movie' as media_type + FROM movies m + WHERE m.has_video_file = TRUE + ORDER BY m.imdb_id + LIMIT 2000 + """) + movies = [dict(row) for row in cursor.fetchall()] + + # Combine episodes and movies + all_items = episodes + movies - # Check each episode's NFO file + # Check each item's NFO file missing_dateadded = [] nfo_manager = dependencies["nfo_manager"] - for ep in episodes: + for item in all_items: try: - # Build expected NFO path - series_path = Path(ep['series_path']) - season_dir = series_path / config.tv_season_dir_format.format(season=ep['season']) + media_type = item['media_type'] + item_path = Path(item['series_path']) - if not season_dir.exists(): + if media_type == 'episode': + # Handle TV episodes + season_dir = item_path / config.tv_season_dir_format.format(season=item['season']) + + if not season_dir.exists(): + continue + + # Find NFO file for this episode + nfo_files = list(season_dir.glob(f"*S{item['season']:02d}E{item['episode']:02d}*.nfo")) + if not nfo_files: + continue + + nfo_path = nfo_files[0] # Use first match + + elif media_type == 'movie': + # Handle movies + if not item_path.exists(): + continue + + # Find NFO file for this movie + nfo_files = list(item_path.glob("*.nfo")) + if not nfo_files: + continue + + nfo_path = nfo_files[0] # Use first match + else: continue - # Find NFO file for this episode - nfo_files = list(season_dir.glob(f"*S{ep['season']:02d}E{ep['episode']:02d}*.nfo")) - if not nfo_files: - continue - - nfo_path = nfo_files[0] # Use first match - # Parse NFO and check for dateadded try: import xml.etree.ElementTree as ET @@ -1585,17 +1615,31 @@ async def get_episodes_missing_nfo_dateadded(dependencies: dict): root = tree.getroot() dateadded_elem = root.find('dateadded') - if dateadded_elem is None or not dateadded_elem.text: - missing_dateadded.append({ - **ep, - 'nfo_path': str(nfo_path), - 'nfo_exists': True, - 'dateadded_in_nfo': False - }) + # Check if dateadded is missing or empty + has_dateadded = dateadded_elem is not None and dateadded_elem.text and dateadded_elem.text.strip() + + # If NFO is missing dateadded, check if item should have a date + if not has_dateadded: + # Item should have a date if it has one in the database, or if it has aired date + should_have_date = ( + item['dateadded'] is not None or + (media_type == 'episode' and item.get('aired')) or + media_type == 'movie' # Movies should generally have dateadded + ) + + if should_have_date: + missing_dateadded.append({ + **item, + 'nfo_path': str(nfo_path), + 'nfo_exists': True, + 'dateadded_in_nfo': False, + 'should_have_date': True + }) + except ET.ParseError: # NFO file is corrupted missing_dateadded.append({ - **ep, + **item, 'nfo_path': str(nfo_path), 'nfo_exists': True, 'dateadded_in_nfo': False, @@ -1603,14 +1647,19 @@ async def get_episodes_missing_nfo_dateadded(dependencies: dict): }) except Exception as e: - print(f"Error checking NFO for {ep['imdb_id']} S{ep['season']:02d}E{ep['episode']:02d}: {e}") + if item['media_type'] == 'episode': + print(f"Error checking NFO for {item['imdb_id']} S{item['season']:02d}E{item['episode']:02d}: {e}") + else: + print(f"Error checking NFO for movie {item['imdb_id']}: {e}") continue return { "success": True, "total_episodes_checked": len(episodes), + "total_movies_checked": len(movies), + "total_items_checked": len(all_items), "missing_dateadded_count": len(missing_dateadded), - "episodes": missing_dateadded[:50] # Limit display to first 50 + "items": missing_dateadded[:50] # Limit display to first 50 } except Exception as e: diff --git a/nfoguard-web/static/index.html b/nfoguard-web/static/index.html index 614caf4..d4860b9 100644 --- a/nfoguard-web/static/index.html +++ b/nfoguard-web/static/index.html @@ -533,6 +533,6 @@
- + \ No newline at end of file diff --git a/nfoguard-web/static/js/app.js b/nfoguard-web/static/js/app.js index dea032a..1eb8e5a 100644 --- a/nfoguard-web/static/js/app.js +++ b/nfoguard-web/static/js/app.js @@ -1836,20 +1836,23 @@ async function checkMissingNFODates() { let html = `

NFO Scan Results

-

Total episodes checked: ${response.total_episodes_checked}

-

Episodes missing dateadded in NFO: ${response.missing_dateadded_count}

+

Total episodes checked: ${response.total_episodes_checked || 0}

+

Total movies checked: ${response.total_movies_checked || 0}

+

Total items checked: ${response.total_items_checked || 0}

+

Items missing dateadded in NFO: ${response.missing_dateadded_count}

`; if (response.missing_dateadded_count > 0) { html += `
-
Episodes with missing dateadded (showing first 50):
+
Items with missing dateadded (showing first 50):
- + + @@ -1860,15 +1863,17 @@ async function checkMissingNFODates() { `; - response.episodes.forEach(ep => { + (response.items || response.episodes || []).forEach(item => { + const displayDate = item.dateadded ? new Date(item.dateadded).toLocaleString() : 'None'; html += ` - - - - - - + + + + + + + `; });
SeriesTypeIMDb ID Season Episode Database Date
${ep.imdb_id}${ep.season}${ep.episode}${new Date(ep.dateadded).toLocaleString()}${ep.source}${ep.nfo_path}${item.media_type || 'episode'}${item.imdb_id}${item.season || 'N/A'}${item.episode || 'N/A'}${displayDate}${item.source || 'unknown'}${item.nfo_path}