diff --git a/processors/__init__.py b/processors/__init__.py index e69de29..a77ac42 100644 --- a/processors/__init__.py +++ b/processors/__init__.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python3 +""" +Processing components for NFOGuard +""" + +from .tv_processor import TVProcessor +from .movie_processor import MovieProcessor + +__all__ = ['TVProcessor', 'MovieProcessor'] \ No newline at end of file diff --git a/processors/movie_processor.py b/processors/movie_processor.py new file mode 100644 index 0000000..3766d1a --- /dev/null +++ b/processors/movie_processor.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 +""" +Movie processing logic for NFOGuard +""" +import os +from pathlib import Path +from typing import Optional, Dict, Any, List +from datetime import datetime, timezone + +# Import core components +from core.database import NFOGuardDatabase +from core.nfo_manager import NFOManager +from core.path_mapper import PathMapper +from core.logging import _log +from clients.radarr_client import RadarrClient +from clients.external_clients import ExternalClientManager +from config.settings import config + + +class MovieProcessor: + """Handles movie processing and validation""" + + def __init__(self, db: NFOGuardDatabase, nfo_manager: NFOManager, path_mapper: PathMapper): + self.db = db + self.nfo_manager = nfo_manager + self.path_mapper = path_mapper + self.radarr = RadarrClient( + os.environ.get("RADARR_URL", ""), + os.environ.get("RADARR_API_KEY", "") + ) + self.external_clients = ExternalClientManager() + + # NOTE: This is a placeholder extraction - the full 500-line class implementation + # needs to be copied from the original nfoguard.py file (lines 1062-1561) + # + # Key methods that need to be extracted include: + # - process_movie() + # - validate_batch_movies() + # - get_movie_dates() + # - _should_query_external_apis() + # - Various helper methods for date handling and processing + # + # This placeholder allows the import structure to work while we continue + # the refactoring process. + + def process_movie(self, movie_path: Path, imdb_id: str = None) -> bool: + """Process a single movie - PLACEHOLDER""" + _log("INFO", f"Processing movie: {movie_path}") + # Full implementation needs to be copied from original file + return True + + def validate_batch_movies(self, movie_paths: List[Path]) -> Dict[str, Any]: + """Validate batch of movies - PLACEHOLDER""" + _log("INFO", f"Validating {len(movie_paths)} movies") + # Full implementation needs to be copied from original file + return {"processed": 0, "errors": []} + + def get_movie_dates(self, imdb_id: str, movie_path: Path = None) -> Dict[str, Any]: + """Get movie dates from various sources - PLACEHOLDER""" + _log("DEBUG", f"Getting dates for movie {imdb_id}") + # Full implementation needs to be copied from original file + return {"source": "placeholder", "dateadded": None} \ No newline at end of file diff --git a/processors/tv_processor.py b/processors/tv_processor.py new file mode 100644 index 0000000..e331f18 --- /dev/null +++ b/processors/tv_processor.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 +""" +TV Show processing logic for NFOGuard +""" +import os +import glob +from pathlib import Path +from typing import Optional, Dict, Any, List, Tuple +from datetime import datetime, timezone, timedelta + +# Import core components +from core.database import NFOGuardDatabase +from core.nfo_manager import NFOManager +from core.path_mapper import PathMapper +from core.logging import _log +from clients.sonarr_client import SonarrClient +from clients.external_clients import ExternalClientManager +from config.settings import config + + +class TVProcessor: + """Handles TV series processing""" + + def __init__(self, db: NFOGuardDatabase, nfo_manager: NFOManager, path_mapper: PathMapper): + self.db = db + self.nfo_manager = nfo_manager + self.path_mapper = path_mapper + self.sonarr = SonarrClient( + os.environ.get("SONARR_URL", ""), + os.environ.get("SONARR_API_KEY", "") + ) + self.external_clients = ExternalClientManager() + + def find_series_path(self, series_title: str, imdb_id: str, sonarr_path: str = None) -> Optional[Path]: + """Find series directory path""" + # Try webhook path first + if sonarr_path: + container_path = self.path_mapper.sonarr_path_to_container_path(sonarr_path) + path_obj = Path(container_path) + if path_obj.exists(): + return path_obj + + # Search by IMDb ID or title + for media_path in config.tv_paths: + if not media_path.exists(): + continue + + # Search by IMDb ID + if imdb_id: + pattern = str(media_path / f"*[imdb-{imdb_id}]*") + matches = glob.glob(pattern) + if matches: + return Path(matches[0]) + + # Search by title + if series_title: + title_clean = series_title.lower().replace(" ", "").replace("-", "") + for item in media_path.iterdir(): + if item.is_dir() and "[imdb-" in item.name.lower(): + item_clean = item.name.lower().replace(" ", "").replace("-", "") + if title_clean in item_clean: + return item + + return None + + # NOTE: This is a placeholder extraction - the full 763-line class implementation + # needs to be copied from the original nfoguard.py file (lines 299-1061) + # + # Key methods that need to be extracted include: + # - process_series() + # - process_webhook_episodes() + # - process_season() + # - _process_episode() + # - _gather_episode_dates() + # - _extract_title_from_filename() + # - _get_episode_metadata() + # - Various helper methods for date handling and processing + # + # This placeholder allows the import structure to work while we continue + # the refactoring process. + + def process_series(self, series_path: Path) -> None: + """Process a TV series directory - PLACEHOLDER""" + _log("INFO", f"Processing TV series: {series_path}") + # Full implementation needs to be copied from original file + pass + + def process_webhook_episodes(self, series_path: Path, episodes_data: List[Dict]) -> None: + """Process specific episodes from webhook data - PLACEHOLDER""" + _log("INFO", f"Processing {len(episodes_data)} episodes for series: {series_path}") + # Full implementation needs to be copied from original file + pass \ No newline at end of file diff --git a/webhooks/__init__.py b/webhooks/__init__.py index e69de29..b5cdc9d 100644 --- a/webhooks/__init__.py +++ b/webhooks/__init__.py @@ -0,0 +1,8 @@ +#!/usr/bin/env python3 +""" +Webhook processing components for NFOGuard +""" + +from .webhook_batcher import WebhookBatcher + +__all__ = ['WebhookBatcher'] \ No newline at end of file diff --git a/webhooks/webhook_batcher.py b/webhooks/webhook_batcher.py new file mode 100644 index 0000000..6514ff5 --- /dev/null +++ b/webhooks/webhook_batcher.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 +""" +Webhook batch processing logic for NFOGuard +""" +import asyncio +from collections import defaultdict +from datetime import datetime, timedelta +from pathlib import Path +from typing import Dict, Set, List, Any, Optional + +from core.logging import _log +from core.nfo_manager import NFOManager + + +class WebhookBatcher: + """Batches webhook processing to reduce duplicate work""" + + def __init__(self, nfo_manager: NFOManager): + self.nfo_manager = nfo_manager + self.pending: Dict[str, Dict] = {} + self.batch_timeout = 30 + self.processing_lock = asyncio.Lock() + + # NOTE: This is a placeholder extraction - the full 139-line class implementation + # needs to be copied from the original nfoguard.py file (lines 1562-1700) + # + # Key methods that need to be extracted include: + # - queue_sonarr_webhook() + # - queue_radarr_webhook() + # - _start_batch_timer() + # - _process_batched_webhooks() + # - Various helper methods for webhook processing + # + # This placeholder allows the import structure to work while we continue + # the refactoring process. + + async def queue_sonarr_webhook(self, webhook_data: Dict[str, Any]) -> None: + """Queue Sonarr webhook for batch processing - PLACEHOLDER""" + _log("INFO", f"Queuing Sonarr webhook: {webhook_data.get('eventType', 'Unknown')}") + # Full implementation needs to be copied from original file + pass + + async def queue_radarr_webhook(self, webhook_data: Dict[str, Any]) -> None: + """Queue Radarr webhook for batch processing - PLACEHOLDER""" + _log("INFO", f"Queuing Radarr webhook: {webhook_data.get('eventType', 'Unknown')}") + # Full implementation needs to be copied from original file + pass \ No newline at end of file