diff --git a/videoarchiver/__init__.py b/videoarchiver/__init__.py index 1e5f0e9..e820e48 100644 --- a/videoarchiver/__init__.py +++ b/videoarchiver/__init__.py @@ -39,10 +39,10 @@ importlib.reload(videoarchiver.processor) import videoarchiver.queue importlib.reload(videoarchiver.queue) -from videoarchiver.core.base import VideoArchiver -from videoarchiver.core.initialization import initialize_cog, init_callback -from videoarchiver.core.cleanup import cleanup_resources -from videoarchiver.utils.exceptions import ( +from .core.base import VideoArchiver +from .core.initialization import initialize_cog, init_callback +from .core.cleanup import cleanup_resources +from .utils.exceptions import ( VideoArchiverError, CommandError, EventError, @@ -51,12 +51,12 @@ from videoarchiver.utils.exceptions import ( ErrorSeverity, ProcessingError ) -from videoarchiver.database import VideoArchiveDB -from videoarchiver.ffmpeg import FFmpegManager -from videoarchiver.queue import EnhancedVideoQueueManager -from videoarchiver.processor import VideoProcessor -from videoarchiver.config_manager import ConfigManager -from videoarchiver.update_checker import UpdateChecker +from .database import VideoArchiveDB +from .ffmpeg import FFmpegManager +from .queue import EnhancedVideoQueueManager +from .processor import VideoProcessor +from .config_manager import ConfigManager +from .update_checker import UpdateChecker logger = logging.getLogger("VideoArchiver") diff --git a/videoarchiver/commands.py b/videoarchiver/commands.py index 103074b..91542fb 100644 --- a/videoarchiver/commands.py +++ b/videoarchiver/commands.py @@ -1,4 +1,4 @@ """Re-export commands from core.base""" -from videoarchiver.core.base import VideoArchiver +from .core.base import VideoArchiver __all__ = ['VideoArchiver'] diff --git a/videoarchiver/config/__init__.py b/videoarchiver/config/__init__.py index 855a08e..5b5bd2c 100644 --- a/videoarchiver/config/__init__.py +++ b/videoarchiver/config/__init__.py @@ -1,6 +1,6 @@ """Configuration management module""" -from videoarchiver.config.exceptions import ( +from .exceptions import ( ConfigurationError, ValidationError, PermissionError, @@ -10,10 +10,10 @@ from videoarchiver.config.exceptions import ( SchemaError, DiscordAPIError, ) -from videoarchiver.config.channel_manager import ChannelManager -from videoarchiver.config.role_manager import RoleManager -from videoarchiver.config.settings_formatter import SettingsFormatter -from videoarchiver.config.validation_manager import ValidationManager +from .channel_manager import ChannelManager +from .role_manager import RoleManager +from .settings_formatter import SettingsFormatter +from .validation_manager import ValidationManager __all__ = [ 'ConfigurationError', diff --git a/videoarchiver/config/channel_manager.py b/videoarchiver/config/channel_manager.py index f577206..0477b31 100644 --- a/videoarchiver/config/channel_manager.py +++ b/videoarchiver/config/channel_manager.py @@ -4,7 +4,7 @@ import logging from typing import Dict, List, Optional, Tuple import discord -from videoarchiver.config.exceptions import ( +from .exceptions import ( ConfigurationError as ConfigError, DiscordAPIError, ) diff --git a/videoarchiver/config/role_manager.py b/videoarchiver/config/role_manager.py index 24f9567..5f3c4e6 100644 --- a/videoarchiver/config/role_manager.py +++ b/videoarchiver/config/role_manager.py @@ -4,7 +4,7 @@ import logging from typing import Dict, List, Set, Tuple, Optional, Any import discord -from videoarchiver.config.exceptions import ConfigurationError as ConfigError +from .exceptions import ConfigurationError as ConfigError logger = logging.getLogger("RoleManager") diff --git a/videoarchiver/config/settings_formatter.py b/videoarchiver/config/settings_formatter.py index c722032..7430b08 100644 --- a/videoarchiver/config/settings_formatter.py +++ b/videoarchiver/config/settings_formatter.py @@ -5,7 +5,7 @@ from typing import Dict, Any, List from datetime import datetime import discord -from videoarchiver.config.exceptions import ConfigurationError as ConfigError +from .config.exceptions import ConfigurationError as ConfigError logger = logging.getLogger("SettingsFormatter") diff --git a/videoarchiver/config/validation_manager.py b/videoarchiver/config/validation_manager.py index 2b7726e..49dda8f 100644 --- a/videoarchiver/config/validation_manager.py +++ b/videoarchiver/config/validation_manager.py @@ -2,7 +2,7 @@ import logging from typing import Any, Dict, List, Union -from videoarchiver.config.exceptions import ConfigurationError as ConfigError +from .exceptions import ConfigurationError as ConfigError logger = logging.getLogger("ConfigValidation") diff --git a/videoarchiver/config_manager.py b/videoarchiver/config_manager.py index 2ae05f9..8571091 100644 --- a/videoarchiver/config_manager.py +++ b/videoarchiver/config_manager.py @@ -6,11 +6,11 @@ from typing import Dict, Any, Optional, List, Union import discord from redbot.core import Config -from videoarchiver.config.validation_manager import ValidationManager -from videoarchiver.config.settings_formatter import SettingsFormatter -from videoarchiver.config.channel_manager import ChannelManager -from videoarchiver.config.role_manager import RoleManager -from videoarchiver.utils.exceptions import ConfigurationError as ConfigError +from .config.validation_manager import ValidationManager +from .config.settings_formatter import SettingsFormatter +from .config.channel_manager import ChannelManager +from .config.role_manager import RoleManager +from .utils.exceptions import ConfigurationError as ConfigError logger = logging.getLogger("VideoArchiver") diff --git a/videoarchiver/core/__init__.py b/videoarchiver/core/__init__.py index 977ca1f..f8b4c04 100644 --- a/videoarchiver/core/__init__.py +++ b/videoarchiver/core/__init__.py @@ -1,5 +1,5 @@ """Core module for VideoArchiver cog""" -from videoarchiver.core.base import VideoArchiver +from .core.base import VideoArchiver __all__ = ["VideoArchiver"] diff --git a/videoarchiver/core/base.py b/videoarchiver/core/base.py index ebd8200..9c171df 100644 --- a/videoarchiver/core/base.py +++ b/videoarchiver/core/base.py @@ -12,22 +12,22 @@ import discord from redbot.core.bot import Red from redbot.core.commands import GroupCog, Context -from videoarchiver.core.settings import Settings -from videoarchiver.core.lifecycle import LifecycleManager, LifecycleState -from videoarchiver.core.component_manager import ComponentManager, ComponentState -from videoarchiver.core.error_handler import error_manager, handle_command_error -from videoarchiver.core.response_handler import response_manager -from videoarchiver.core.commands.archiver_commands import setup_archiver_commands -from videoarchiver.core.commands.database_commands import setup_database_commands -from videoarchiver.core.commands.settings_commands import setup_settings_commands -from videoarchiver.core.events import setup_events, EventManager +from .settings import Settings +from .lifecycle import LifecycleManager, LifecycleState +from .component_manager import ComponentManager, ComponentState +from .error_handler import error_manager, handle_command_error +from .response_handler import response_manager +from .commands.archiver_commands import setup_archiver_commands +from .commands.database_commands import setup_database_commands +from .commands.settings_commands import setup_settings_commands +from .events import setup_events, EventManager -from videoarchiver.processor.core import Processor -from videoarchiver.queue.manager import QueueManager -from videoarchiver.ffmpeg.ffmpeg_manager import FFmpegManager -from videoarchiver.database.video_archive_db import VideoArchiveDB -from videoarchiver.config_manager import ConfigManager -from videoarchiver.utils.exceptions import ( +from .processor.core import Processor +from .queue.manager import QueueManager +from .ffmpeg.ffmpeg_manager import FFmpegManager +from .database.video_archive_db import VideoArchiveDB +from .config_manager import ConfigManager +from .utils.exceptions import ( CogError, ErrorContext, ErrorSeverity diff --git a/videoarchiver/core/cleanup.py b/videoarchiver/core/cleanup.py index b093cec..95996c0 100644 --- a/videoarchiver/core/cleanup.py +++ b/videoarchiver/core/cleanup.py @@ -8,15 +8,15 @@ from enum import Enum, auto from pathlib import Path from typing import TYPE_CHECKING, Dict, Any, Optional, TypedDict, ClassVar -from videoarchiver.utils.file_ops import cleanup_downloads -from videoarchiver.utils.exceptions import ( +from .utils.file_ops import cleanup_downloads +from .utils.exceptions import ( CleanupError, ErrorContext, ErrorSeverity ) if TYPE_CHECKING: - from videoarchiver.core.base import VideoArchiver + from .base import VideoArchiver logger = logging.getLogger("VideoArchiver") diff --git a/videoarchiver/core/commands.py b/videoarchiver/core/commands.py index 76db984..3784193 100644 --- a/videoarchiver/core/commands.py +++ b/videoarchiver/core/commands.py @@ -6,7 +6,7 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: - from videoarchiver.core.base import VideoArchiver + from .base import VideoArchiver def setup_commands(cog: "VideoArchiver") -> None: """Command setup is now handled in the VideoArchiver class""" diff --git a/videoarchiver/core/commands/__init__.py b/videoarchiver/core/commands/__init__.py index dc42e30..e7f5fce 100644 --- a/videoarchiver/core/commands/__init__.py +++ b/videoarchiver/core/commands/__init__.py @@ -1,8 +1,8 @@ """Command handlers for VideoArchiver""" -from videoarchiver.core.commands.archiver_commands import setup_archiver_commands -from videoarchiver.core.commands.database_commands import setup_database_commands -from videoarchiver.core.commands.settings_commands import setup_settings_commands +from .core.commands.archiver_commands import setup_archiver_commands +from .core.commands.database_commands import setup_database_commands +from .core.commands.settings_commands import setup_settings_commands __all__ = [ 'setup_archiver_commands', diff --git a/videoarchiver/core/commands/archiver_commands.py b/videoarchiver/core/commands/archiver_commands.py index 7062440..930f01b 100644 --- a/videoarchiver/core/commands/archiver_commands.py +++ b/videoarchiver/core/commands/archiver_commands.py @@ -9,8 +9,8 @@ from discord import app_commands from redbot.core import commands from redbot.core.commands import Context, hybrid_group, guild_only, admin_or_permissions -from videoarchiver.core.response_handler import handle_response, ResponseType -from videoarchiver.utils.exceptions import ( +from .core.response_handler import handle_response, ResponseType +from .utils.exceptions import ( CommandError, ErrorContext, ErrorSeverity diff --git a/videoarchiver/core/commands/database_commands.py b/videoarchiver/core/commands/database_commands.py index 45e0fd7..119613c 100644 --- a/videoarchiver/core/commands/database_commands.py +++ b/videoarchiver/core/commands/database_commands.py @@ -10,14 +10,14 @@ from discord import app_commands from redbot.core import commands from redbot.core.commands import Context, hybrid_group, guild_only, admin_or_permissions -from videoarchiver.core.response_handler import handle_response, ResponseType -from videoarchiver.utils.exceptions import ( +from .core.response_handler import handle_response, ResponseType +from .utils.exceptions import ( CommandError, ErrorContext, ErrorSeverity, DatabaseError ) -from videoarchiver.database.video_archive_db import VideoArchiveDB +from .database.video_archive_db import VideoArchiveDB logger = logging.getLogger("VideoArchiver") diff --git a/videoarchiver/core/commands/settings_commands.py b/videoarchiver/core/commands/settings_commands.py index f16899d..eff7794 100644 --- a/videoarchiver/core/commands/settings_commands.py +++ b/videoarchiver/core/commands/settings_commands.py @@ -9,9 +9,9 @@ from discord import app_commands from redbot.core import commands from redbot.core.commands import Context, hybrid_group, guild_only, admin_or_permissions -from videoarchiver.core.settings import VideoFormat, VideoQuality -from videoarchiver.core.response_handler import handle_response, ResponseType -from videoarchiver.utils.exceptions import ( +from .core.settings import VideoFormat, VideoQuality +from .core.response_handler import handle_response, ResponseType +from .utils.exceptions import ( CommandError, ErrorContext, ErrorSeverity diff --git a/videoarchiver/core/component_manager.py b/videoarchiver/core/component_manager.py index 6c6acee..c5de998 100644 --- a/videoarchiver/core/component_manager.py +++ b/videoarchiver/core/component_manager.py @@ -2,27 +2,36 @@ import logging import asyncio -from typing import Dict, Any, Optional, Set, List, TypedDict, ClassVar, Type, Union, Protocol +from typing import ( + Dict, + Any, + Optional, + Set, + List, + TypedDict, + ClassVar, + Type, + Union, + Protocol, +) from enum import Enum, auto from datetime import datetime from pathlib import Path import importlib -from videoarchiver.utils.exceptions import ( - ComponentError, - ErrorContext, - ErrorSeverity -) -from videoarchiver.utils.path_manager import ensure_directory -from videoarchiver.config_manager import ConfigManager -from videoarchiver.processor.core import Processor -from videoarchiver.queue.manager import EnhancedVideoQueueManager -from videoarchiver.ffmpeg.ffmpeg_manager import FFmpegManager +from .utils.exceptions import ComponentError, ErrorContext, ErrorSeverity +from .utils.path_manager import ensure_directory +from .config_manager import ConfigManager +from .processor.core import Processor +from .queue.manager import EnhancedVideoQueueManager +from .ffmpeg.ffmpeg_manager import FFmpegManager logger = logging.getLogger("VideoArchiver") + class ComponentState(Enum): """Possible states of a component""" + UNREGISTERED = auto() REGISTERED = auto() INITIALIZING = auto() @@ -30,16 +39,20 @@ class ComponentState(Enum): ERROR = auto() SHUTDOWN = auto() + class ComponentHistory(TypedDict): """Type definition for component history entry""" + component: str state: str timestamp: str error: Optional[str] duration: float + class ComponentStatus(TypedDict): """Type definition for component status""" + state: str registration_time: Optional[str] initialization_time: Optional[str] @@ -48,8 +61,10 @@ class ComponentStatus(TypedDict): error: Optional[str] health: bool + class Initializable(Protocol): """Protocol for initializable components""" + async def initialize(self) -> None: """Initialize the component""" ... @@ -58,6 +73,7 @@ class Initializable(Protocol): """Shutdown the component""" ... + class Component: """Base class for managed components""" @@ -74,7 +90,7 @@ class Component: async def initialize(self) -> None: """ Initialize the component. - + Raises: ComponentError: If initialization fails """ @@ -83,7 +99,7 @@ class Component: async def shutdown(self) -> None: """ Shutdown the component. - + Raises: ComponentError: If shutdown fails """ @@ -98,6 +114,7 @@ class Component: """Check if component is healthy""" return self.state == ComponentState.READY and not self.error + class ComponentTracker: """Tracks component states and relationships""" @@ -108,14 +125,11 @@ class ComponentTracker: self.history: List[ComponentHistory] = [] def update_state( - self, - name: str, - state: ComponentState, - error: Optional[str] = None + self, name: str, state: ComponentState, error: Optional[str] = None ) -> None: """Update component state""" self.states[name] = state - + # Add history entry now = datetime.utcnow() duration = 0.0 @@ -124,24 +138,24 @@ class ComponentTracker: last_time = datetime.fromisoformat(last_entry["timestamp"]) duration = (now - last_time).total_seconds() - self.history.append(ComponentHistory( - component=name, - state=state.name, - timestamp=now.isoformat(), - error=error, - duration=duration - )) + self.history.append( + ComponentHistory( + component=name, + state=state.name, + timestamp=now.isoformat(), + error=error, + duration=duration, + ) + ) # Cleanup old history if len(self.history) > self.MAX_HISTORY: - self.history = self.history[-self.MAX_HISTORY:] + self.history = self.history[-self.MAX_HISTORY :] def get_component_history(self, name: str) -> List[ComponentHistory]: """Get state history for a component""" - return [ - entry for entry in self.history - if entry["component"] == name - ] + return [entry for entry in self.history if entry["component"] == name] + class DependencyManager: """Manages component dependencies""" @@ -153,11 +167,11 @@ class DependencyManager: def add_dependency(self, component: str, dependency: str) -> None: """ Add a dependency relationship. - + Args: component: Component name dependency: Dependency name - + Raises: ComponentError: If dependency cycle is detected """ @@ -169,8 +183,8 @@ class DependencyManager: "DependencyManager", "add_dependency", {"component": component, "dependency": dependency}, - ErrorSeverity.HIGH - ) + ErrorSeverity.HIGH, + ), ) if component not in self.dependencies: @@ -192,8 +206,7 @@ class DependencyManager: return False visited.add(start) return any( - has_path(dep, end) - for dep in self.dependencies.get(start, set()) + has_path(dep, end) for dep in self.dependencies.get(start, set()) ) return has_path(dependency, component) @@ -209,10 +222,10 @@ class DependencyManager: def get_initialization_order(self) -> List[str]: """ Get components in dependency order. - + Returns: List of component names in initialization order - + Raises: ComponentError: If dependency cycle is detected """ @@ -223,8 +236,7 @@ class DependencyManager: def visit(component: str) -> None: if component in temp_visited: cycle = " -> ".join( - name for name in self.dependencies - if name in temp_visited + name for name in self.dependencies if name in temp_visited ) raise ComponentError( f"Dependency cycle detected: {cycle}", @@ -232,8 +244,8 @@ class DependencyManager: "DependencyManager", "get_initialization_order", {"cycle": cycle}, - ErrorSeverity.HIGH - ) + ErrorSeverity.HIGH, + ), ) if component in visited: return @@ -256,12 +268,13 @@ class DependencyManager: "DependencyManager", "get_initialization_order", None, - ErrorSeverity.HIGH - ) + ErrorSeverity.HIGH, + ), ) return order + class ComponentManager: """Manages VideoArchiver components""" @@ -269,7 +282,7 @@ class ComponentManager: "config_manager": (ConfigManager, set()), "processor": (Processor, {"config_manager"}), "queue_manager": (EnhancedVideoQueueManager, {"config_manager"}), - "ffmpeg_mgr": (FFmpegManager, set()) + "ffmpeg_mgr": (FFmpegManager, set()), } def __init__(self, cog: Any) -> None: @@ -282,16 +295,16 @@ class ComponentManager: self, name: str, component: Union[Component, Any], - dependencies: Optional[Set[str]] = None + dependencies: Optional[Set[str]] = None, ) -> None: """ Register a component with dependencies. - + Args: name: Component name component: Component instance dependencies: Optional set of dependency names - + Raises: ComponentError: If registration fails """ @@ -314,8 +327,8 @@ class ComponentManager: "ComponentManager", "register", {"component": name, "dependency": dep}, - ErrorSeverity.HIGH - ) + ErrorSeverity.HIGH, + ), ) self.dependency_manager.add_dependency(name, dep) @@ -335,29 +348,29 @@ class ComponentManager: "ComponentManager", "register", {"component": name}, - ErrorSeverity.HIGH - ) + ErrorSeverity.HIGH, + ), ) async def initialize_components(self) -> None: """ Initialize all components in dependency order. - + Raises: ComponentError: If initialization fails """ try: # Initialize core components first await self._initialize_core_components() - + # Get initialization order init_order = self.dependency_manager.get_initialization_order() - + # Initialize remaining components for name in init_order: if name not in self._components: continue - + component = self._components[name] try: self.tracker.update_state(name, ComponentState.INITIALIZING) @@ -374,8 +387,8 @@ class ComponentManager: "ComponentManager", "initialize_components", {"component": name}, - ErrorSeverity.HIGH - ) + ErrorSeverity.HIGH, + ), ) except Exception as e: @@ -387,14 +400,14 @@ class ComponentManager: "ComponentManager", "initialize_components", None, - ErrorSeverity.HIGH - ) + ErrorSeverity.HIGH, + ), ) async def _initialize_core_components(self) -> None: """ Initialize core system components. - + Raises: ComponentError: If core component initialization fails """ @@ -421,14 +434,14 @@ class ComponentManager: "ComponentManager", "_initialize_core_components", None, - ErrorSeverity.HIGH - ) + ErrorSeverity.HIGH, + ), ) async def _initialize_paths(self) -> None: """ Initialize required paths. - + Raises: ComponentError: If path initialization fails """ @@ -450,11 +463,8 @@ class ComponentManager: raise ComponentError( error, context=ErrorContext( - "ComponentManager", - "_initialize_paths", - None, - ErrorSeverity.HIGH - ) + "ComponentManager", "_initialize_paths", None, ErrorSeverity.HIGH + ), ) def get(self, name: str) -> Optional[Component]: @@ -464,17 +474,19 @@ class ComponentManager: async def shutdown_components(self) -> None: """ Shutdown components in reverse dependency order. - + Raises: ComponentError: If shutdown fails """ try: - shutdown_order = reversed(self.dependency_manager.get_initialization_order()) - + shutdown_order = reversed( + self.dependency_manager.get_initialization_order() + ) + for name in shutdown_order: if name not in self._components: continue - + component = self._components[name] try: await component.shutdown() @@ -489,8 +501,8 @@ class ComponentManager: "ComponentManager", "shutdown_components", {"component": name}, - ErrorSeverity.HIGH - ) + ErrorSeverity.HIGH, + ), ) except Exception as e: @@ -499,11 +511,8 @@ class ComponentManager: raise ComponentError( error, context=ErrorContext( - "ComponentManager", - "shutdown_components", - None, - ErrorSeverity.HIGH - ) + "ComponentManager", "shutdown_components", None, ErrorSeverity.HIGH + ), ) def clear(self) -> None: @@ -514,19 +523,27 @@ class ComponentManager: def get_component_status(self) -> Dict[str, ComponentStatus]: """ Get status of all components. - + Returns: Dictionary mapping component names to their status """ return { name: ComponentStatus( state=self.tracker.states.get(name, ComponentState.UNREGISTERED).name, - registration_time=component.registration_time.isoformat() if component.registration_time else None, - initialization_time=component.initialization_time.isoformat() if component.initialization_time else None, + registration_time=( + component.registration_time.isoformat() + if component.registration_time + else None + ), + initialization_time=( + component.initialization_time.isoformat() + if component.initialization_time + else None + ), dependencies=self.dependency_manager.get_dependencies(name), dependents=self.dependency_manager.get_dependents(name), error=component.error, - health=component.is_healthy() + health=component.is_healthy(), ) for name, component in self._components.items() } diff --git a/videoarchiver/core/error_handler.py b/videoarchiver/core/error_handler.py index da4c099..e90835a 100644 --- a/videoarchiver/core/error_handler.py +++ b/videoarchiver/core/error_handler.py @@ -14,7 +14,7 @@ from redbot.core.commands import ( CommandError ) -from videoarchiver.utils.exceptions import ( +from .utils.exceptions import ( VideoArchiverError, ErrorSeverity, ErrorContext, @@ -33,7 +33,7 @@ from videoarchiver.utils.exceptions import ( ResourceExhaustedError, ConfigurationError ) -from videoarchiver.core.response_handler import response_manager +from .core.response_handler import response_manager logger = logging.getLogger("VideoArchiver") diff --git a/videoarchiver/core/events.py b/videoarchiver/core/events.py index 6fb1440..81335a2 100644 --- a/videoarchiver/core/events.py +++ b/videoarchiver/core/events.py @@ -9,15 +9,15 @@ from typing import TYPE_CHECKING, Dict, Any, Optional, TypedDict, ClassVar, List import discord -from videoarchiver.processor.constants import REACTIONS -from videoarchiver.processor.reactions import handle_archived_reaction -from videoarchiver.core.guild import initialize_guild_components, cleanup_guild_components -from videoarchiver.core.error_handler import error_manager -from videoarchiver.core.response_handler import response_manager -from videoarchiver.utils.exceptions import EventError, ErrorContext, ErrorSeverity +from .processor.constants import REACTIONS +from .processor.reactions import handle_archived_reaction +from .core.guild import initialize_guild_components, cleanup_guild_components +from .core.error_handler import error_manager +from .core.response_handler import response_manager +from .utils.exceptions import EventError, ErrorContext, ErrorSeverity if TYPE_CHECKING: - from videoarchiver.core.base import VideoArchiver + from .core.base import VideoArchiver logger = logging.getLogger("VideoArchiver") diff --git a/videoarchiver/core/guild.py b/videoarchiver/core/guild.py index e6954f6..2ec1782 100644 --- a/videoarchiver/core/guild.py +++ b/videoarchiver/core/guild.py @@ -4,13 +4,13 @@ import logging from pathlib import Path from typing import TYPE_CHECKING, Dict, Any, Optional -from videoarchiver.utils.download_core import DownloadCore -from videoarchiver.utils.message_manager import MessageManager -from videoarchiver.utils.file_ops import cleanup_downloads -from videoarchiver.utils.exceptions import VideoArchiverError as ProcessingError +from .utils.download_core import DownloadCore +from .utils.message_manager import MessageManager +from .utils.file_ops import cleanup_downloads +from .utils.exceptions import VideoArchiverError as ProcessingError if TYPE_CHECKING: - from videoarchiver.core.base import VideoArchiver + from .core.base import VideoArchiver logger = logging.getLogger("VideoArchiver") diff --git a/videoarchiver/core/initialization.py b/videoarchiver/core/initialization.py index 5573842..1b49ba9 100644 --- a/videoarchiver/core/initialization.py +++ b/videoarchiver/core/initialization.py @@ -4,15 +4,15 @@ from typing import TYPE_CHECKING, Optional, Dict, Any import asyncio import logging -from videoarchiver.utils.exceptions import ( +from .utils.exceptions import ( ComponentError, ErrorContext, ErrorSeverity ) -from videoarchiver.core.lifecycle import LifecycleState +from .core.lifecycle import LifecycleState if TYPE_CHECKING: - from videoarchiver.core.base import VideoArchiver + from .core.base import VideoArchiver logger = logging.getLogger("VideoArchiver") diff --git a/videoarchiver/core/lifecycle.py b/videoarchiver/core/lifecycle.py index 32f46ed..5bfcca3 100644 --- a/videoarchiver/core/lifecycle.py +++ b/videoarchiver/core/lifecycle.py @@ -7,8 +7,8 @@ from typing import Optional, Dict, Any, Set, List, Callable, TypedDict, ClassVar from enum import Enum, auto from datetime import datetime -from videoarchiver.core.cleanup import cleanup_resources, force_cleanup_resources -from videoarchiver.utils.exceptions import ( +from .core.cleanup import cleanup_resources, force_cleanup_resources +from .utils.exceptions import ( VideoArchiverError, ErrorContext, ErrorSeverity, diff --git a/videoarchiver/core/response_handler.py b/videoarchiver/core/response_handler.py index 4a8b9f2..7245935 100644 --- a/videoarchiver/core/response_handler.py +++ b/videoarchiver/core/response_handler.py @@ -7,7 +7,7 @@ from datetime import datetime import discord from redbot.core.commands import Context -from videoarchiver.utils.exceptions import ErrorSeverity +from .utils.exceptions import ErrorSeverity logger = logging.getLogger("VideoArchiver") diff --git a/videoarchiver/core/settings.py b/videoarchiver/core/settings.py index 0bf9c3f..82b3048 100644 --- a/videoarchiver/core/settings.py +++ b/videoarchiver/core/settings.py @@ -4,7 +4,7 @@ from typing import Dict, Any, List, Optional, Union, TypedDict, ClassVar from dataclasses import dataclass, field from enum import Enum, auto -from videoarchiver.utils.exceptions import ( +from .utils.exceptions import ( ConfigurationError, ErrorContext, ErrorSeverity diff --git a/videoarchiver/database/__init__.py b/videoarchiver/database/__init__.py index 734a891..6925992 100644 --- a/videoarchiver/database/__init__.py +++ b/videoarchiver/database/__init__.py @@ -1,9 +1,9 @@ """Database management package for video archiving""" -from videoarchiver.database.connection_manager import DatabaseConnectionManager -from videoarchiver.database.query_manager import DatabaseQueryManager -from videoarchiver.database.schema_manager import DatabaseSchemaManager -from videoarchiver.database.video_archive_db import VideoArchiveDB +from .connection_manager import DatabaseConnectionManager +from .query_manager import DatabaseQueryManager +from .schema_manager import DatabaseSchemaManager +from .video_archive_db import VideoArchiveDB __all__ = [ 'DatabaseConnectionManager', diff --git a/videoarchiver/database/connection_manager.py b/videoarchiver/database/connection_manager.py index 17eac71..8c680a5 100644 --- a/videoarchiver/database/connection_manager.py +++ b/videoarchiver/database/connection_manager.py @@ -10,7 +10,7 @@ import threading from queue import Queue, Empty from datetime import datetime -from videoarchiver.utils.exceptions import ( +from ..utils.exceptions import ( DatabaseError, ErrorContext, ErrorSeverity diff --git a/videoarchiver/database/schema_manager.py b/videoarchiver/database/schema_manager.py index b7e09c1..7d75e82 100644 --- a/videoarchiver/database/schema_manager.py +++ b/videoarchiver/database/schema_manager.py @@ -7,7 +7,7 @@ from typing import List, Dict, Any, Optional, TypedDict, ClassVar, Union from enum import Enum, auto from datetime import datetime -from videoarchiver.utils.exceptions import DatabaseError, ErrorContext, ErrorSeverity +from ..utils.exceptions import DatabaseError, ErrorContext, ErrorSeverity logger = logging.getLogger("DBSchemaManager") diff --git a/videoarchiver/database/video_archive_db.py b/videoarchiver/database/video_archive_db.py index a74567a..e2fa6d1 100644 --- a/videoarchiver/database/video_archive_db.py +++ b/videoarchiver/database/video_archive_db.py @@ -4,9 +4,9 @@ import logging from pathlib import Path from typing import Optional, Dict, Any, List -from videoarchiver.database.schema_manager import DatabaseSchemaManager -from videoarchiver.database.query_manager import DatabaseQueryManager -from videoarchiver.database.connection_manager import DatabaseConnectionManager +from .schema_manager import DatabaseSchemaManager +from .query_manager import DatabaseQueryManager +from .connection_manager import DatabaseConnectionManager logger = logging.getLogger("VideoArchiverDB") diff --git a/videoarchiver/exceptions.py b/videoarchiver/exceptions.py index 0f3af8a..1b8d8c8 100644 --- a/videoarchiver/exceptions.py +++ b/videoarchiver/exceptions.py @@ -1,6 +1,6 @@ """Base exceptions for VideoArchiver""" -from videoarchiver.utils.exceptions import ( +from .utils.exceptions import ( VideoArchiverError, ConfigurationError, VideoVerificationError, @@ -23,24 +23,24 @@ from videoarchiver.utils.exceptions import ( # Re-export all exceptions __all__ = [ - 'VideoArchiverError', - 'ConfigurationError', - 'VideoVerificationError', - 'QueueError', - 'FileCleanupError', - 'ResourceExhaustedError', - 'ProcessingError', - 'CleanupError', - 'FileOperationError', - 'VideoDownloadError', - 'VideoProcessingError', - 'VideoUploadError', - 'VideoCleanupError', - 'PermissionError', - 'NetworkError', - 'ResourceError', - 'ComponentError', - 'DiscordAPIError', + "VideoArchiverError", + "ConfigurationError", + "VideoVerificationError", + "QueueError", + "FileCleanupError", + "ResourceExhaustedError", + "ProcessingError", + "CleanupError", + "FileOperationError", + "VideoDownloadError", + "VideoProcessingError", + "VideoUploadError", + "VideoCleanupError", + "PermissionError", + "NetworkError", + "ResourceError", + "ComponentError", + "DiscordAPIError", ] # Alias exceptions for backward compatibility diff --git a/videoarchiver/ffmpeg/__init__.py b/videoarchiver/ffmpeg/__init__.py index f7838e4..ca79863 100644 --- a/videoarchiver/ffmpeg/__init__.py +++ b/videoarchiver/ffmpeg/__init__.py @@ -18,12 +18,12 @@ logging.basicConfig( logger = logging.getLogger("VideoArchiver") # Import components after logging is configured -from videoarchiver.ffmpeg.ffmpeg_manager import FFmpegManager -from videoarchiver.ffmpeg.video_analyzer import VideoAnalyzer -from videoarchiver.ffmpeg.gpu_detector import GPUDetector -from videoarchiver.ffmpeg.encoder_params import EncoderParams -from videoarchiver.ffmpeg.ffmpeg_downloader import FFmpegDownloader -from videoarchiver.ffmpeg.exceptions import ( +from .ffmpeg_manager import FFmpegManager +from .video_analyzer import VideoAnalyzer +from .gpu_detector import GPUDetector +from .encoder_params import EncoderParams +from .ffmpeg_downloader import FFmpegDownloader +from .exceptions import ( FFmpegError, DownloadError, VerificationError, diff --git a/videoarchiver/ffmpeg/binary_manager.py b/videoarchiver/ffmpeg/binary_manager.py index 9f06359..bdf9a69 100644 --- a/videoarchiver/ffmpeg/binary_manager.py +++ b/videoarchiver/ffmpeg/binary_manager.py @@ -5,15 +5,15 @@ import os from pathlib import Path from typing import Dict, Optional -from videoarchiver.ffmpeg.exceptions import ( +from .exceptions import ( FFmpegError, DownloadError, VerificationError, PermissionError, FFmpegNotFoundError ) -from videoarchiver.ffmpeg.ffmpeg_downloader import FFmpegDownloader -from videoarchiver.ffmpeg.verification_manager import VerificationManager +from .ffmpeg_downloader import FFmpegDownloader +from .verification_manager import VerificationManager logger = logging.getLogger("FFmpegBinaryManager") diff --git a/videoarchiver/ffmpeg/encoder_params.py b/videoarchiver/ffmpeg/encoder_params.py index bbde85e..1de5ea5 100644 --- a/videoarchiver/ffmpeg/encoder_params.py +++ b/videoarchiver/ffmpeg/encoder_params.py @@ -3,7 +3,7 @@ import os import logging from typing import Dict, Any -from videoarchiver.ffmpeg.exceptions import CompressionError, QualityError, BitrateError +from .exceptions import CompressionError, QualityError, BitrateError logger = logging.getLogger("VideoArchiver") diff --git a/videoarchiver/ffmpeg/ffmpeg_downloader.py b/videoarchiver/ffmpeg/ffmpeg_downloader.py index 5fa1bdb..bc2511d 100644 --- a/videoarchiver/ffmpeg/ffmpeg_downloader.py +++ b/videoarchiver/ffmpeg/ffmpeg_downloader.py @@ -16,7 +16,7 @@ from typing import Optional, Dict, List import time import lzma -from videoarchiver.ffmpeg.exceptions import DownloadError +from .exceptions import DownloadError logger = logging.getLogger("VideoArchiver") diff --git a/videoarchiver/ffmpeg/ffmpeg_manager.py b/videoarchiver/ffmpeg/ffmpeg_manager.py index 452a759..5149a2b 100644 --- a/videoarchiver/ffmpeg/ffmpeg_manager.py +++ b/videoarchiver/ffmpeg/ffmpeg_manager.py @@ -6,17 +6,17 @@ import multiprocessing from pathlib import Path from typing import Dict, Any, Optional -from videoarchiver.ffmpeg.exceptions import ( +from .exceptions import ( FFmpegError, AnalysisError, FFmpegNotFoundError ) -from videoarchiver.ffmpeg.gpu_detector import GPUDetector -from videoarchiver.ffmpeg.video_analyzer import VideoAnalyzer -from videoarchiver.ffmpeg.encoder_params import EncoderParams -from videoarchiver.ffmpeg.process_manager import ProcessManager -from videoarchiver.ffmpeg.verification_manager import VerificationManager -from videoarchiver.ffmpeg.binary_manager import BinaryManager +from .gpu_detector import GPUDetector +from .video_analyzer import VideoAnalyzer +from .encoder_params import EncoderParams +from .process_manager import ProcessManager +from .verification_manager import VerificationManager +from .binary_manager import BinaryManager logger = logging.getLogger("VideoArchiver") diff --git a/videoarchiver/ffmpeg/verification_manager.py b/videoarchiver/ffmpeg/verification_manager.py index 6dbedb3..de2d79c 100644 --- a/videoarchiver/ffmpeg/verification_manager.py +++ b/videoarchiver/ffmpeg/verification_manager.py @@ -6,7 +6,7 @@ import subprocess from pathlib import Path from typing import Dict, List, Optional -from videoarchiver.ffmpeg.exceptions import ( +from .exceptions import ( TimeoutError, VerificationError, EncodingError, diff --git a/videoarchiver/processor.py b/videoarchiver/processor.py index 15ef66f..867afb0 100644 --- a/videoarchiver/processor.py +++ b/videoarchiver/processor.py @@ -1,6 +1,6 @@ """Re-export video processing components from processor module""" -from videoarchiver.processor import ( +from .processor import ( VideoProcessor, REACTIONS, MessageHandler, diff --git a/videoarchiver/processor/__init__.py b/videoarchiver/processor/__init__.py index 7a72c2d..47e8052 100644 --- a/videoarchiver/processor/__init__.py +++ b/videoarchiver/processor/__init__.py @@ -3,8 +3,8 @@ from typing import Dict, Any, Optional, Union, List, Tuple import discord -from videoarchiver.processor.core import VideoProcessor -from videoarchiver.processor.constants import ( +from .processor.core import VideoProcessor +from .processor.constants import ( REACTIONS, ReactionType, ReactionEmojis, @@ -12,7 +12,7 @@ from videoarchiver.processor.constants import ( get_reaction, get_progress_emoji ) -from videoarchiver.processor.url_extractor import ( +from .processor.url_extractor import ( URLExtractor, URLMetadata, URLPattern, @@ -21,7 +21,7 @@ from videoarchiver.processor.url_extractor import ( URLValidator, URLMetadataExtractor ) -from videoarchiver.processor.message_validator import ( +from .processor.message_validator import ( MessageValidator, ValidationContext, ValidationRule, @@ -32,15 +32,15 @@ from videoarchiver.processor.message_validator import ( ValidationCacheEntry, ValidationError ) -from videoarchiver.processor.message_handler import MessageHandler -from videoarchiver.processor.queue_handler import QueueHandler -from videoarchiver.processor.reactions import ( +from .processor.message_handler import MessageHandler +from .processor.queue_handler import QueueHandler +from .processor.reactions import ( handle_archived_reaction, update_queue_position_reaction, update_progress_reaction, update_download_progress_reaction ) -from videoarchiver.utils import progress_tracker +from .utils import progress_tracker # Export public classes and constants __all__ = [ diff --git a/videoarchiver/processor/cleanup_manager.py b/videoarchiver/processor/cleanup_manager.py index e4667c4..ea69ba1 100644 --- a/videoarchiver/processor/cleanup_manager.py +++ b/videoarchiver/processor/cleanup_manager.py @@ -18,9 +18,9 @@ from typing import ( ) from datetime import datetime, timedelta -from videoarchiver.processor.queue_handler import QueueHandler -from videoarchiver.ffmpeg.ffmpeg_manager import FFmpegManager -from videoarchiver.utils.exceptions import CleanupError +from .processor.queue_handler import QueueHandler +from .ffmpeg.ffmpeg_manager import FFmpegManager +from .utils.exceptions import CleanupError logger = logging.getLogger("VideoArchiver") diff --git a/videoarchiver/processor/core.py b/videoarchiver/processor/core.py index 32efb2b..2a510a3 100644 --- a/videoarchiver/processor/core.py +++ b/videoarchiver/processor/core.py @@ -8,17 +8,17 @@ from datetime import datetime, timedelta import discord from discord.ext import commands -from videoarchiver.processor.message_handler import MessageHandler -from videoarchiver.processor.queue_handler import QueueHandler -from videoarchiver.utils import progress_tracker -from videoarchiver.processor.status_display import StatusDisplay -from videoarchiver.processor.cleanup_manager import CleanupManager, CleanupStrategy -from videoarchiver.processor.constants import REACTIONS -from videoarchiver.queue.manager import EnhancedVideoQueueManager -from videoarchiver.ffmpeg.ffmpeg_manager import FFmpegManager -from videoarchiver.database.video_archive_db import VideoArchiveDB -from videoarchiver.config_manager import ConfigManager -from videoarchiver.utils.exceptions import ProcessorError +from .processor.message_handler import MessageHandler +from .processor.queue_handler import QueueHandler +from .utils import progress_tracker +from .processor.status_display import StatusDisplay +from .processor.cleanup_manager import CleanupManager, CleanupStrategy +from .processor.constants import REACTIONS +from .queue.manager import EnhancedVideoQueueManager +from .ffmpeg.ffmpeg_manager import FFmpegManager +from .database.video_archive_db import VideoArchiveDB +from .config_manager import ConfigManager +from .utils.exceptions import ProcessorError logger = logging.getLogger("VideoArchiver") diff --git a/videoarchiver/processor/message_handler.py b/videoarchiver/processor/message_handler.py index 9a44277..eeec96f 100644 --- a/videoarchiver/processor/message_handler.py +++ b/videoarchiver/processor/message_handler.py @@ -8,13 +8,13 @@ from datetime import datetime, timedelta import discord from discord.ext import commands -from videoarchiver.processor.url_extractor import URLExtractor, URLMetadata -from videoarchiver.processor.message_validator import MessageValidator, ValidationError -from videoarchiver.processor.queue_processor import QueueProcessor, QueuePriority -from videoarchiver.processor.constants import REACTIONS -from videoarchiver.queue.manager import EnhancedVideoQueueManager -from videoarchiver.config_manager import ConfigManager -from videoarchiver.utils.exceptions import MessageHandlerError +from .processor.url_extractor import URLExtractor, URLMetadata +from .processor.message_validator import MessageValidator, ValidationError +from .processor.queue_processor import QueueProcessor, QueuePriority +from .processor.constants import REACTIONS +from .queue.manager import EnhancedVideoQueueManager +from .config_manager import ConfigManager +from .utils.exceptions import MessageHandlerError logger = logging.getLogger("VideoArchiver") diff --git a/videoarchiver/processor/message_validator.py b/videoarchiver/processor/message_validator.py index df14e12..f0320ee 100644 --- a/videoarchiver/processor/message_validator.py +++ b/videoarchiver/processor/message_validator.py @@ -7,7 +7,7 @@ from typing import Dict, Optional, Tuple, List, Any, Callable, Set, TypedDict, C from datetime import datetime import discord -from videoarchiver.utils.exceptions import ValidationError +from .utils.exceptions import ValidationError logger = logging.getLogger("VideoArchiver") diff --git a/videoarchiver/processor/queue_handler.py b/videoarchiver/processor/queue_handler.py index 691a43e..8d934d1 100644 --- a/videoarchiver/processor/queue_handler.py +++ b/videoarchiver/processor/queue_handler.py @@ -8,14 +8,14 @@ from typing import Optional, Dict, Any, List, Tuple, Set, TypedDict, ClassVar, C from datetime import datetime import discord -from videoarchiver.utils import progress_tracker -from videoarchiver.database.video_archive_db import VideoArchiveDB -from videoarchiver.utils.download_manager import DownloadManager -from videoarchiver.utils.message_manager import MessageManager -from videoarchiver.utils.exceptions import QueueHandlerError -from videoarchiver.queue.models import QueueItem -from videoarchiver.config_manager import ConfigManager -from videoarchiver.processor.constants import REACTIONS +from .utils import progress_tracker +from .database.video_archive_db import VideoArchiveDB +from .utils.download_manager import DownloadManager +from .utils.message_manager import MessageManager +from .utils.exceptions import QueueHandlerError +from .queue.models import QueueItem +from .config_manager import ConfigManager +from .processor.constants import REACTIONS logger = logging.getLogger("VideoArchiver") diff --git a/videoarchiver/processor/queue_processor.py b/videoarchiver/processor/queue_processor.py index 0e690b2..017db60 100644 --- a/videoarchiver/processor/queue_processor.py +++ b/videoarchiver/processor/queue_processor.py @@ -7,11 +7,11 @@ from typing import List, Optional, Dict, Any, Set, Union, TypedDict, ClassVar from datetime import datetime import discord -from videoarchiver.queue.models import QueueItem -from videoarchiver.queue.manager import EnhancedVideoQueueManager -from videoarchiver.processor.constants import REACTIONS -from videoarchiver.processor.url_extractor import URLMetadata -from videoarchiver.utils.exceptions import QueueProcessingError +from .queue.models import QueueItem +from .queue.manager import EnhancedVideoQueueManager +from .processor.constants import REACTIONS +from .processor.url_extractor import URLMetadata +from .utils.exceptions import QueueProcessingError logger = logging.getLogger("VideoArchiver") diff --git a/videoarchiver/processor/reactions.py b/videoarchiver/processor/reactions.py index c8b3b56..6581d99 100644 --- a/videoarchiver/processor/reactions.py +++ b/videoarchiver/processor/reactions.py @@ -7,8 +7,8 @@ from typing import List, Optional import discord from urllib.parse import urlparse -from videoarchiver.processor.constants import REACTIONS, ReactionType, get_reaction, get_progress_emoji -from videoarchiver.database.video_archive_db import VideoArchiveDB +from .processor.constants import REACTIONS, ReactionType, get_reaction, get_progress_emoji +from .database.video_archive_db import VideoArchiveDB logger = logging.getLogger("VideoArchiver") diff --git a/videoarchiver/processor/status_display.py b/videoarchiver/processor/status_display.py index a921247..dccba69 100644 --- a/videoarchiver/processor/status_display.py +++ b/videoarchiver/processor/status_display.py @@ -7,7 +7,7 @@ from datetime import datetime from typing import Dict, Any, List, Optional, Callable, TypeVar, Union, TypedDict, ClassVar, Tuple import discord -from videoarchiver.utils.exceptions import DisplayError +from .utils.exceptions import DisplayError logger = logging.getLogger("VideoArchiver") diff --git a/videoarchiver/queue/__init__.py b/videoarchiver/queue/__init__.py index 9ada58c..b690bda 100644 --- a/videoarchiver/queue/__init__.py +++ b/videoarchiver/queue/__init__.py @@ -1,10 +1,10 @@ """Queue management package for video processing""" -from videoarchiver.queue.models import QueueItem, QueueMetrics -from videoarchiver.queue.manager import EnhancedVideoQueueManager -from videoarchiver.queue.persistence import QueuePersistenceManager, QueueError -from videoarchiver.queue.monitoring import QueueMonitor, MonitoringError -from videoarchiver.queue.cleanup import QueueCleaner, CleanupError +from .models import QueueItem, QueueMetrics +from .manager import EnhancedVideoQueueManager +from .persistence import QueuePersistenceManager, QueueError +from .monitoring import QueueMonitor, MonitoringError +from .cleanup import QueueCleaner, CleanupError __all__ = [ 'QueueItem', diff --git a/videoarchiver/queue/cleaners/__init__.py b/videoarchiver/queue/cleaners/__init__.py index dbb9787..a51cb5b 100644 --- a/videoarchiver/queue/cleaners/__init__.py +++ b/videoarchiver/queue/cleaners/__init__.py @@ -1,8 +1,8 @@ """Queue cleaning functionality""" -from videoarchiver.queue.cleaners.guild_cleaner import GuildCleaner -from videoarchiver.queue.cleaners.history_cleaner import HistoryCleaner -from videoarchiver.queue.cleaners.tracking_cleaner import TrackingCleaner +from .guild_cleaner import GuildCleaner +from .history_cleaner import HistoryCleaner +from .tracking_cleaner import TrackingCleaner __all__ = [ 'GuildCleaner', diff --git a/videoarchiver/queue/cleaners/guild_cleaner.py b/videoarchiver/queue/cleaners/guild_cleaner.py index f202554..54914f4 100644 --- a/videoarchiver/queue/cleaners/guild_cleaner.py +++ b/videoarchiver/queue/cleaners/guild_cleaner.py @@ -7,7 +7,7 @@ from dataclasses import dataclass, field from typing import Dict, List, Set, Tuple, Any, Optional from datetime import datetime -from videoarchiver.queue.models import QueueItem +from ..models import QueueItem logger = logging.getLogger("GuildCleaner") diff --git a/videoarchiver/queue/cleaners/history_cleaner.py b/videoarchiver/queue/cleaners/history_cleaner.py index 6c291a3..6284d05 100644 --- a/videoarchiver/queue/cleaners/history_cleaner.py +++ b/videoarchiver/queue/cleaners/history_cleaner.py @@ -6,7 +6,7 @@ from dataclasses import dataclass, field from typing import Dict, Optional, List, Any, Set from datetime import datetime, timedelta -from videoarchiver.queue.models import QueueItem +from ..models import QueueItem logger = logging.getLogger("HistoryCleaner") diff --git a/videoarchiver/queue/cleaners/tracking_cleaner.py b/videoarchiver/queue/cleaners/tracking_cleaner.py index b9b38fb..83e15dd 100644 --- a/videoarchiver/queue/cleaners/tracking_cleaner.py +++ b/videoarchiver/queue/cleaners/tracking_cleaner.py @@ -7,7 +7,7 @@ from dataclasses import dataclass, field from typing import Dict, List, Set, Tuple, Any, Optional from datetime import datetime -from videoarchiver.queue.models import QueueItem +from ..models import QueueItem logger = logging.getLogger("TrackingCleaner") diff --git a/videoarchiver/queue/cleanup.py b/videoarchiver/queue/cleanup.py index 11558d7..10c9816 100644 --- a/videoarchiver/queue/cleanup.py +++ b/videoarchiver/queue/cleanup.py @@ -7,16 +7,16 @@ from dataclasses import dataclass, field from typing import Dict, List, Set, Optional, Any, Tuple from datetime import datetime, timedelta -from videoarchiver.queue.models import QueueItem, QueueMetrics -from videoarchiver.queue.cleaners.history_cleaner import ( +from .models import QueueItem, QueueMetrics +from .cleaners.history_cleaner import ( HistoryCleaner, CleanupStrategy as HistoryStrategy ) -from videoarchiver.queue.cleaners.guild_cleaner import ( +from .cleaners.guild_cleaner import ( GuildCleaner, GuildCleanupStrategy ) -from videoarchiver.queue.cleaners.tracking_cleaner import ( +from .cleaners.tracking_cleaner import ( TrackingCleaner, TrackingCleanupStrategy ) diff --git a/videoarchiver/queue/manager.py b/videoarchiver/queue/manager.py index 5fba1e9..7be07c2 100644 --- a/videoarchiver/queue/manager.py +++ b/videoarchiver/queue/manager.py @@ -7,13 +7,13 @@ from dataclasses import dataclass, field from typing import Optional, Tuple, Dict, Any, List, Set, Callable from datetime import datetime, timedelta -from videoarchiver.queue.state_manager import QueueStateManager -from videoarchiver.queue.processor import QueueProcessor -from videoarchiver.queue.metrics_manager import QueueMetricsManager -from videoarchiver.queue.persistence import QueuePersistenceManager -from videoarchiver.queue.monitoring import QueueMonitor, MonitoringLevel -from videoarchiver.queue.cleanup import QueueCleaner -from videoarchiver.queue.models import QueueItem, QueueError, CleanupError +from .state_manager import QueueStateManager +from .processor import QueueProcessor +from .metrics_manager import QueueMetricsManager +from .persistence import QueuePersistenceManager +from .monitoring import QueueMonitor, MonitoringLevel +from .cleanup import QueueCleaner +from .models import QueueItem, QueueError, CleanupError logger = logging.getLogger("QueueManager") diff --git a/videoarchiver/queue/monitoring.py b/videoarchiver/queue/monitoring.py index f629b3f..b81a19d 100644 --- a/videoarchiver/queue/monitoring.py +++ b/videoarchiver/queue/monitoring.py @@ -8,8 +8,8 @@ from dataclasses import dataclass, field from typing import Optional, Dict, Any, List, Set from datetime import datetime, timedelta -from videoarchiver.queue.health_checker import HealthChecker, HealthStatus, HealthCategory -from videoarchiver.queue.recovery_manager import RecoveryManager, RecoveryStrategy +from .health_checker import HealthChecker, HealthStatus, HealthCategory +from .recovery_manager import RecoveryManager, RecoveryStrategy logger = logging.getLogger("QueueMonitoring") diff --git a/videoarchiver/queue/persistence.py b/videoarchiver/queue/persistence.py index 4b52fdb..5078bc0 100644 --- a/videoarchiver/queue/persistence.py +++ b/videoarchiver/queue/persistence.py @@ -8,7 +8,8 @@ import fcntl import asyncio from datetime import datetime, timedelta from typing import Dict, Any, Optional -from videoarchiver.queue.models import QueueItem, QueueMetrics + +from .models import QueueItem, QueueMetrics # Configure logging logging.basicConfig( @@ -16,6 +17,7 @@ logging.basicConfig( ) logger = logging.getLogger("QueuePersistence") + class QueuePersistenceManager: """Manages persistence of queue state to disk""" @@ -25,10 +27,10 @@ class QueuePersistenceManager: max_retries: int = 3, retry_delay: int = 1, backup_interval: int = 3600, # 1 hour - max_backups: int = 24 # Keep last 24 backups + max_backups: int = 24, # Keep last 24 backups ): """Initialize the persistence manager - + Args: persistence_path: Path to the persistence file max_retries: Maximum number of retries for file operations @@ -50,17 +52,17 @@ class QueuePersistenceManager: processing: Dict[str, QueueItem], completed: Dict[str, QueueItem], failed: Dict[str, QueueItem], - metrics: QueueMetrics + metrics: QueueMetrics, ) -> None: """Persist queue state to disk with improved error handling - + Args: queue: List of pending queue items processing: Dict of items currently being processed completed: Dict of completed items failed: Dict of failed items metrics: Queue metrics object - + Raises: QueueError: If persistence fails """ @@ -87,14 +89,14 @@ class QueuePersistenceManager: "compression_failures": metrics.compression_failures, "hardware_accel_failures": metrics.hardware_accel_failures, }, - "timestamp": datetime.utcnow().isoformat() + "timestamp": datetime.utcnow().isoformat(), } # Ensure directory exists os.makedirs(os.path.dirname(self.persistence_path), exist_ok=True) # Acquire file lock - lock_fd = open(self._lock_file, 'w') + lock_fd = open(self._lock_file, "w") fcntl.flock(lock_fd.fileno(), fcntl.LOCK_EX) # Write with retries @@ -120,7 +122,9 @@ class QueuePersistenceManager: except Exception as e: if attempt == self.max_retries - 1: raise - logger.warning(f"Retry {attempt + 1}/{self.max_retries} failed: {e}") + logger.warning( + f"Retry {attempt + 1}/{self.max_retries} failed: {e}" + ) await asyncio.sleep(self.retry_delay) except Exception as e: @@ -140,18 +144,25 @@ class QueuePersistenceManager: # Create backup timestamp = datetime.utcnow().strftime("%Y%m%d_%H%M%S") backup_path = f"{self.persistence_path}.bak.{timestamp}" - with open(self.persistence_path, "rb") as src, open(backup_path, "wb") as dst: + with open(self.persistence_path, "rb") as src, open( + backup_path, "wb" + ) as dst: dst.write(src.read()) dst.flush() os.fsync(dst.fileno()) # Clean old backups - backup_files = sorted([ - f for f in os.listdir(os.path.dirname(self.persistence_path)) - if f.startswith(os.path.basename(self.persistence_path) + ".bak.") - ]) + backup_files = sorted( + [ + f + for f in os.listdir(os.path.dirname(self.persistence_path)) + if f.startswith(os.path.basename(self.persistence_path) + ".bak.") + ] + ) while len(backup_files) > self.max_backups: - old_backup = os.path.join(os.path.dirname(self.persistence_path), backup_files.pop(0)) + old_backup = os.path.join( + os.path.dirname(self.persistence_path), backup_files.pop(0) + ) try: os.remove(old_backup) except Exception as e: @@ -162,10 +173,10 @@ class QueuePersistenceManager: def load_queue_state(self) -> Optional[Dict[str, Any]]: """Load persisted queue state from disk with retries - + Returns: Dict containing queue state if successful, None if file doesn't exist - + Raises: QueueError: If loading fails """ @@ -175,7 +186,7 @@ class QueuePersistenceManager: lock_fd = None try: # Acquire file lock - lock_fd = open(self._lock_file, 'w') + lock_fd = open(self._lock_file, "w") fcntl.flock(lock_fd.fileno(), fcntl.LOCK_EX) # Try loading main file @@ -188,18 +199,28 @@ class QueuePersistenceManager: break except Exception as e: last_error = e - logger.warning(f"Retry {attempt + 1}/{self.max_retries} failed: {e}") + logger.warning( + f"Retry {attempt + 1}/{self.max_retries} failed: {e}" + ) time.sleep(self.retry_delay) # If main file failed, try loading latest backup if state is None: - backup_files = sorted([ - f for f in os.listdir(os.path.dirname(self.persistence_path)) - if f.startswith(os.path.basename(self.persistence_path) + ".bak.") - ], reverse=True) + backup_files = sorted( + [ + f + for f in os.listdir(os.path.dirname(self.persistence_path)) + if f.startswith( + os.path.basename(self.persistence_path) + ".bak." + ) + ], + reverse=True, + ) if backup_files: - latest_backup = os.path.join(os.path.dirname(self.persistence_path), backup_files[0]) + latest_backup = os.path.join( + os.path.dirname(self.persistence_path), backup_files[0] + ) try: with open(latest_backup, "r") as f: state = json.load(f) @@ -207,7 +228,9 @@ class QueuePersistenceManager: except Exception as e: logger.error(f"Failed to load backup: {e}") if last_error: - raise QueueError(f"Failed to load queue state: {last_error}") + raise QueueError( + f"Failed to load queue state: {last_error}" + ) raise if state is None: @@ -218,22 +241,34 @@ class QueuePersistenceManager: try: if isinstance(item_data, dict): # Ensure datetime fields are properly formatted - for field in ['added_at', 'last_retry', 'last_error_time']: + for field in ["added_at", "last_retry", "last_error_time"]: if field in item_data and item_data[field]: if isinstance(item_data[field], str): try: - item_data[field] = datetime.fromisoformat(item_data[field]) + item_data[field] = datetime.fromisoformat( + item_data[field] + ) except ValueError: - item_data[field] = datetime.utcnow() if field == 'added_at' else None + item_data[field] = ( + datetime.utcnow() + if field == "added_at" + else None + ) elif not isinstance(item_data[field], datetime): - item_data[field] = datetime.utcnow() if field == 'added_at' else None + item_data[field] = ( + datetime.utcnow() + if field == "added_at" + else None + ) # Ensure processing_time is a float - if 'processing_time' in item_data: + if "processing_time" in item_data: try: - item_data['processing_time'] = float(item_data['processing_time']) + item_data["processing_time"] = float( + item_data["processing_time"] + ) except (ValueError, TypeError): - item_data['processing_time'] = 0.0 + item_data["processing_time"] = 0.0 return QueueItem(**item_data) return None @@ -283,15 +318,21 @@ class QueuePersistenceManager: backup_path = f"{self.persistence_path}.corrupted.{int(time.time())}" try: os.rename(self.persistence_path, backup_path) - logger.info(f"Created backup of corrupted state file: {backup_path}") + logger.info( + f"Created backup of corrupted state file: {backup_path}" + ) except Exception as be: - logger.error(f"Failed to create backup of corrupted state file: {str(be)}") + logger.error( + f"Failed to create backup of corrupted state file: {str(be)}" + ) raise QueueError(f"Failed to load queue state: {str(e)}") finally: if lock_fd: fcntl.flock(lock_fd.fileno(), fcntl.LOCK_UN) lock_fd.close() + class QueueError(Exception): """Base exception for queue-related errors""" + pass diff --git a/videoarchiver/queue/processor.py b/videoarchiver/queue/processor.py index f523cef..305e337 100644 --- a/videoarchiver/queue/processor.py +++ b/videoarchiver/queue/processor.py @@ -8,9 +8,9 @@ from dataclasses import dataclass from typing import Callable, Optional, Tuple, List, Set, Dict, Any from datetime import datetime, timedelta -from videoarchiver.queue.models import QueueItem -from videoarchiver.queue.state_manager import QueueStateManager, ItemState -from videoarchiver.queue.monitoring import QueueMonitor +from .models import QueueItem +from .state_manager import QueueStateManager, ItemState +from .monitoring import QueueMonitor logger = logging.getLogger("QueueProcessor") diff --git a/videoarchiver/queue/recovery_manager.py b/videoarchiver/queue/recovery_manager.py index 3296052..8998210 100644 --- a/videoarchiver/queue/recovery_manager.py +++ b/videoarchiver/queue/recovery_manager.py @@ -7,7 +7,7 @@ from dataclasses import dataclass, field from typing import List, Tuple, Dict, Optional, Any, Set from datetime import datetime, timedelta -from videoarchiver.queue.models import QueueItem +from .models import QueueItem logger = logging.getLogger("QueueRecoveryManager") diff --git a/videoarchiver/queue/state_manager.py b/videoarchiver/queue/state_manager.py index 7125918..f6e325a 100644 --- a/videoarchiver/queue/state_manager.py +++ b/videoarchiver/queue/state_manager.py @@ -7,7 +7,7 @@ from dataclasses import dataclass from typing import Dict, Set, List, Optional, Any from datetime import datetime -from videoarchiver.queue.models import QueueItem, QueueMetrics +from .models import QueueItem, QueueMetrics logger = logging.getLogger("QueueStateManager") diff --git a/videoarchiver/update_checker.py b/videoarchiver/update_checker.py index 22427b4..05a2bd8 100644 --- a/videoarchiver/update_checker.py +++ b/videoarchiver/update_checker.py @@ -15,7 +15,7 @@ import tempfile import os import shutil -from videoarchiver.exceptions import UpdateError +from .exceptions import UpdateError logger = logging.getLogger('VideoArchiver') diff --git a/videoarchiver/utils/__init__.py b/videoarchiver/utils/__init__.py index 14dfdf1..cd7eab2 100644 --- a/videoarchiver/utils/__init__.py +++ b/videoarchiver/utils/__init__.py @@ -2,27 +2,27 @@ from typing import Dict, Optional, Any, Union, List -from videoarchiver.utils.file_ops import ( +from .utils.file_ops import ( cleanup_downloads, ensure_directory, get_file_size, is_valid_path, safe_delete ) -from videoarchiver.utils.file_deletion import FileDeleter -from videoarchiver.utils.directory_manager import DirectoryManager -from videoarchiver.utils.permission_manager import PermissionManager -from videoarchiver.utils.download_manager import DownloadManager -from videoarchiver.utils.compression_manager import CompressionManager -from videoarchiver.utils.progress_tracker import ( +from .utils.file_deletion import FileDeleter +from .utils.directory_manager import DirectoryManager +from .utils.permission_manager import PermissionManager +from .utils.download_manager import DownloadManager +from .utils.compression_manager import CompressionManager +from .utils.progress_tracker import ( ProgressTracker, ProgressStatus, DownloadProgress, CompressionProgress, CompressionParams ) -from videoarchiver.utils.path_manager import PathManager -from videoarchiver.utils.exceptions import ( +from .utils.path_manager import PathManager +from .utils.exceptions import ( # Base exception VideoArchiverError, ErrorSeverity, diff --git a/videoarchiver/utils/compression_handler.py b/videoarchiver/utils/compression_handler.py index 34968e9..f0b32c4 100644 --- a/videoarchiver/utils/compression_handler.py +++ b/videoarchiver/utils/compression_handler.py @@ -7,11 +7,11 @@ import subprocess from datetime import datetime from typing import Dict, Optional, Callable, Set, Tuple -from videoarchiver.ffmpeg.ffmpeg_manager import FFmpegManager -from videoarchiver.ffmpeg.exceptions import CompressionError -from videoarchiver.utils.exceptions import VideoVerificationError -from videoarchiver.utils.file_operations import FileOperations -from videoarchiver.utils.progress_handler import ProgressHandler +from .ffmpeg.ffmpeg_manager import FFmpegManager +from .ffmpeg.exceptions import CompressionError +from .utils.exceptions import VideoVerificationError +from .utils.file_operations import FileOperations +from .utils.progress_handler import ProgressHandler logger = logging.getLogger("VideoArchiver") diff --git a/videoarchiver/utils/compression_manager.py b/videoarchiver/utils/compression_manager.py index ef1f9d1..1cab33b 100644 --- a/videoarchiver/utils/compression_manager.py +++ b/videoarchiver/utils/compression_manager.py @@ -7,11 +7,11 @@ import subprocess from datetime import datetime from typing import Dict, Any, Optional, Callable, List, Set, Tuple -from videoarchiver.processor import _compression_progress -from videoarchiver.utils.compression_handler import CompressionHandler -from videoarchiver.utils.progress_handler import ProgressHandler -from videoarchiver.utils.file_operations import FileOperations -from videoarchiver.utils.exceptions import CompressionError, VideoVerificationError +from .processor import _compression_progress +from .utils.compression_handler import CompressionHandler +from .utils.progress_handler import ProgressHandler +from .utils.file_operations import FileOperations +from .utils.exceptions import CompressionError, VideoVerificationError logger = logging.getLogger("VideoArchiver") diff --git a/videoarchiver/utils/directory_manager.py b/videoarchiver/utils/directory_manager.py index ed6fb42..fee7aa9 100644 --- a/videoarchiver/utils/directory_manager.py +++ b/videoarchiver/utils/directory_manager.py @@ -6,8 +6,8 @@ import asyncio from pathlib import Path from typing import List, Optional, Tuple -from videoarchiver.utils.exceptions import FileCleanupError -from videoarchiver.utils.file_deletion import SecureFileDeleter +from .utils.exceptions import FileCleanupError +from .utils.file_deletion import SecureFileDeleter logger = logging.getLogger("DirectoryManager") diff --git a/videoarchiver/utils/download_core.py b/videoarchiver/utils/download_core.py index 9340c05..6139ef2 100644 --- a/videoarchiver/utils/download_core.py +++ b/videoarchiver/utils/download_core.py @@ -7,12 +7,12 @@ import yt_dlp from typing import Dict, Optional, Callable, Tuple from pathlib import Path -from videoarchiver.utils.url_validator import check_url_support -from videoarchiver.utils.progress_handler import ProgressHandler, CancellableYTDLLogger -from videoarchiver.utils.file_operations import FileOperations -from videoarchiver.utils.compression_handler import CompressionHandler -from videoarchiver.utils.process_manager import ProcessManager -from videoarchiver.ffmpeg.ffmpeg_manager import FFmpegManager +from .utils.url_validator import check_url_support +from .utils.progress_handler import ProgressHandler, CancellableYTDLLogger +from .utils.file_operations import FileOperations +from .utils.compression_handler import CompressionHandler +from .utils.process_manager import ProcessManager +from .ffmpeg.ffmpeg_manager import FFmpegManager logger = logging.getLogger("VideoArchiver") diff --git a/videoarchiver/utils/download_manager.py b/videoarchiver/utils/download_manager.py index 54a68f6..a56ec0c 100644 --- a/videoarchiver/utils/download_manager.py +++ b/videoarchiver/utils/download_manager.py @@ -9,9 +9,9 @@ from concurrent.futures import ThreadPoolExecutor from typing import Dict, List, Optional, Tuple, Callable, Any from pathlib import Path -from videoarchiver.utils.verification_manager import VideoVerificationManager -from videoarchiver.utils.compression_manager import CompressionManager -from videoarchiver.utils import progress_tracker +from .utils.verification_manager import VideoVerificationManager +from .utils.compression_manager import CompressionManager +from .utils import progress_tracker logger = logging.getLogger("DownloadManager") diff --git a/videoarchiver/utils/file_deletion.py b/videoarchiver/utils/file_deletion.py index b9db683..a3100a4 100644 --- a/videoarchiver/utils/file_deletion.py +++ b/videoarchiver/utils/file_deletion.py @@ -7,7 +7,7 @@ import logging from pathlib import Path from typing import Optional -from videoarchiver.utils.exceptions import FileCleanupError +from .utils.exceptions import FileCleanupError logger = logging.getLogger("FileDeleter") diff --git a/videoarchiver/utils/file_operations.py b/videoarchiver/utils/file_operations.py index c4f1d5f..099e9e5 100644 --- a/videoarchiver/utils/file_operations.py +++ b/videoarchiver/utils/file_operations.py @@ -9,8 +9,8 @@ import subprocess from typing import Tuple from pathlib import Path -from videoarchiver.utils.exceptions import VideoVerificationError -from videoarchiver.utils.file_deletion import secure_delete_file +from .utils.exceptions import VideoVerificationError +from .utils.file_deletion import secure_delete_file logger = logging.getLogger("VideoArchiver") diff --git a/videoarchiver/utils/file_ops.py b/videoarchiver/utils/file_ops.py index c78e859..08c7690 100644 --- a/videoarchiver/utils/file_ops.py +++ b/videoarchiver/utils/file_ops.py @@ -4,10 +4,10 @@ import logging from pathlib import Path from typing import List, Tuple, Optional -from videoarchiver.utils.exceptions import FileCleanupError -from videoarchiver.utils.file_deletion import SecureFileDeleter -from videoarchiver.utils.directory_manager import DirectoryManager -from videoarchiver.utils.permission_manager import PermissionManager +from .utils.exceptions import FileCleanupError +from .utils.file_deletion import SecureFileDeleter +from .utils.directory_manager import DirectoryManager +from .utils.permission_manager import PermissionManager logger = logging.getLogger("VideoArchiver") diff --git a/videoarchiver/utils/path_manager.py b/videoarchiver/utils/path_manager.py index 5a78407..0a980c7 100644 --- a/videoarchiver/utils/path_manager.py +++ b/videoarchiver/utils/path_manager.py @@ -10,8 +10,8 @@ import time from typing import Generator, List, Optional from pathlib import Path -from videoarchiver.utils.exceptions import FileCleanupError -from videoarchiver.utils.permission_manager import PermissionManager +from .utils.exceptions import FileCleanupError +from .utils.permission_manager import PermissionManager logger = logging.getLogger("PathManager") diff --git a/videoarchiver/utils/permission_manager.py b/videoarchiver/utils/permission_manager.py index 5bd7925..5a388fd 100644 --- a/videoarchiver/utils/permission_manager.py +++ b/videoarchiver/utils/permission_manager.py @@ -6,7 +6,7 @@ import logging from pathlib import Path from typing import Optional, Union, List -from videoarchiver.utils.exceptions import FileCleanupError +from .utils.exceptions import FileCleanupError logger = logging.getLogger("PermissionManager")