improv: phase 1 of faster scan and tracking of scans
Local Docker Build (Dev) / build-dev (push) Successful in 4s

This commit is contained in:
2025-10-18 15:16:02 -04:00
parent beb471d081
commit 55d5f891b5
3 changed files with 122 additions and 16 deletions
+81 -6
View File
@@ -53,22 +53,96 @@ class TVProcessor:
path_mapper=self.path_mapper
)
def process_series(self, series_path: Path) -> None:
def should_skip_series(self, imdb_id: str, episodes_on_disk: int, series_name: str = "") -> Tuple[bool, str]:
"""
Determine if we should skip processing this series based on completion status
Args:
imdb_id: Series IMDb ID
episodes_on_disk: Number of episodes found on disk
series_name: Series name for logging
Returns:
(should_skip: bool, reason: str)
"""
try:
with self.db.get_connection() as conn:
cursor = conn.cursor()
if self.db.db_type == "postgresql":
cursor.execute("""
SELECT
COUNT(*) as total_in_db,
COUNT(CASE WHEN dateadded IS NOT NULL AND source IS NOT NULL AND source != 'unknown' AND source != 'no_valid_date_source' THEN 1 END) as complete_episodes
FROM episodes
WHERE imdb_id = %s
""", (imdb_id,))
else:
cursor.execute("""
SELECT
COUNT(*) as total_in_db,
COUNT(CASE WHEN dateadded IS NOT NULL AND dateadded != '' AND source IS NOT NULL AND source != 'unknown' AND source != 'no_valid_date_source' THEN 1 END) as complete_episodes
FROM episodes
WHERE imdb_id = ?
""", (imdb_id,))
result = cursor.fetchone()
if not result:
return False, "No database records found"
if self.db.db_type == "postgresql":
total_in_db = result['total_in_db']
complete_episodes = result['complete_episodes']
else:
total_in_db = result[0]
complete_episodes = result[1]
# Skip if:
# 1. We have episodes in database
# 2. Database count matches disk count (no missing episodes)
# 3. All episodes have valid dates and sources
if total_in_db > 0 and total_in_db == episodes_on_disk and complete_episodes == episodes_on_disk:
return True, f"Complete: {complete_episodes}/{episodes_on_disk} episodes have valid dates"
elif total_in_db == 0:
return False, f"New series: No episodes in database"
elif total_in_db != episodes_on_disk:
return False, f"Disk mismatch: {total_in_db} in DB vs {episodes_on_disk} on disk"
else:
return False, f"Incomplete: {complete_episodes}/{episodes_on_disk} episodes have valid dates"
except Exception as e:
_log("ERROR", f"Error checking series completion for {imdb_id}: {e}")
return False, f"Error checking completion: {e}"
def process_series(self, series_path: Path, force_scan: bool = False) -> str:
"""Process a TV series directory"""
imdb_id = self.nfo_manager.parse_imdb_from_path(series_path)
if not imdb_id:
_log("ERROR", f"No IMDb ID found in series path: {series_path}")
return
return "error"
_log("INFO", f"Processing TV series: {series_path.name}")
# Update database
self.db.upsert_series(imdb_id, str(series_path))
# Find video files
# Find video files first to check completion
disk_episodes = find_episodes_on_disk(series_path)
_log("INFO", f"Found {len(disk_episodes)} episodes on disk")
# Check if we should skip this series (unless forced)
if not force_scan:
should_skip, reason = self.should_skip_series(imdb_id, len(disk_episodes), series_path.name)
if should_skip:
_log("INFO", f"⏭️ SKIPPING SERIES: {series_path.name} [{imdb_id}] - {reason}")
# Still update the series record to track that we've seen it
self.db.upsert_series(imdb_id, str(series_path))
return "skipped"
else:
_log("INFO", f"📺 PROCESSING SERIES: {series_path.name} [{imdb_id}] - {reason}")
else:
_log("INFO", f"🔄 FORCE PROCESSING SERIES: {series_path.name} [{imdb_id}] - Force scan enabled")
# Update database
self.db.upsert_series(imdb_id, str(series_path))
# Get episode dates
episode_dates = self._gather_episode_dates(series_path, imdb_id, disk_episodes)
@@ -110,6 +184,7 @@ class TVProcessor:
pass
_log("INFO", f"Completed processing TV series: {series_path.name}")
return "processed"
def _extract_series_title_from_path(self, series_path: Path) -> Optional[str]:
"""Extract series title from directory path using unified file utilities"""