fixed imports again

This commit is contained in:
pacnpal
2024-11-18 01:21:40 +00:00
parent d03e8dc8e8
commit fc06e54d8a
37 changed files with 879 additions and 882 deletions

View File

@@ -91,25 +91,25 @@ try:
)
except ImportError:
# Fall back to absolute imports if relative imports fail
from videoarchiver import utils
from videoarchiver import processor
from videoarchiver import queue
from videoarchiver import ffmpeg
from videoarchiver import database
from videoarchiver import config
from videoarchiver import core
# from videoarchiver import utils
# from videoarchiver import processor
# from videoarchiver import queue
# from videoarchiver import ffmpeg
# from videoarchiver import database
# from videoarchiver import config
# from videoarchiver import core
# 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 (
VideoArchiverError,
CommandError,
EventError,
CogError,
ErrorContext,
ErrorSeverity,
ProcessingError,
)
# VideoArchiverError,
# CommandError,
# EventError,
# CogError,
# ErrorContext,
# ErrorSeverity,
# ProcessingError,
# )
# Reload all modules
importlib.reload(utils)

View File

@@ -1,6 +1,6 @@
"""Configuration management module"""
try:
# try:
# Try relative imports first
from .exceptions import (
ConfigurationError,
@@ -16,34 +16,35 @@ try:
from .role_manager import RoleManager
from .settings_formatter import SettingsFormatter
from .validation_manager import ValidationManager
except ImportError:
# except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.config.exceptions import (
ConfigurationError,
ValidationError,
PermissionError,
LoadError,
SaveError,
MigrationError,
SchemaError,
DiscordAPIError,
)
# ConfigurationError,
# ValidationError,
# PermissionError,
# LoadError,
# SaveError,
# MigrationError,
# 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
__all__ = [
'ConfigurationError',
'ValidationError',
'PermissionError',
'LoadError',
'SaveError',
'MigrationError',
'SchemaError',
'DiscordAPIError',
'ChannelManager',
'RoleManager',
'SettingsFormatter',
'ValidationManager',
"ConfigurationError",
"ValidationError",
"PermissionError",
"LoadError",
"SaveError",
"MigrationError",
"SchemaError",
"DiscordAPIError",
"ChannelManager",
"RoleManager",
"SettingsFormatter",
"ValidationManager",
]

View File

@@ -4,18 +4,19 @@ import logging
from typing import Dict, List, Optional, Tuple
import discord # type: ignore
try:
# try:
# Try relative imports first
from .exceptions import (
ConfigurationError as ConfigError,
DiscordAPIError,
)
except ImportError:
# except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.config.exceptions import (
ConfigurationError as ConfigError,
DiscordAPIError,
)
# ConfigurationError as ConfigError,
# DiscordAPIError,
# )
logger = logging.getLogger("ChannelManager")

View File

@@ -4,10 +4,11 @@ import logging
from typing import Dict, List, Set, Tuple, Optional, Any
import discord # type: ignore
try:
# try:
# Try relative imports first
from .exceptions import ConfigurationError as ConfigError
except ImportError:
# except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.config.exceptions import ConfigurationError as ConfigError
@@ -21,8 +22,7 @@ class RoleManager:
self.config_manager = config_manager
async def check_user_roles(
self,
member: discord.Member
self, member: discord.Member
) -> Tuple[bool, Optional[str]]:
"""Check if user has permission based on allowed roles
@@ -37,8 +37,7 @@ class RoleManager:
"""
try:
allowed_roles = await self.config_manager.get_setting(
member.guild.id,
"allowed_roles"
member.guild.id, "allowed_roles"
)
# If no roles are set, allow all users
@@ -53,21 +52,16 @@ class RoleManager:
return True, None
# Get role names for error message
missing_roles = await self._get_role_names(
member.guild,
allowed_role_set
)
missing_roles = await self._get_role_names(member.guild, allowed_role_set)
return False, f"Missing required roles: {', '.join(missing_roles)}"
except Exception as e:
logger.error(f"Failed to check roles for user {member.id} in guild {member.guild.id}: {e}")
logger.error(
f"Failed to check roles for user {member.id} in guild {member.guild.id}: {e}"
)
raise ConfigError(f"Failed to check user roles: {str(e)}")
async def add_allowed_role(
self,
guild_id: int,
role_id: int
) -> None:
async def add_allowed_role(self, guild_id: int, role_id: int) -> None:
"""Add a role to allowed roles
Args:
@@ -78,20 +72,12 @@ class RoleManager:
ConfigError: If role cannot be added
"""
try:
await self.config_manager.add_to_list(
guild_id,
"allowed_roles",
role_id
)
await self.config_manager.add_to_list(guild_id, "allowed_roles", role_id)
except Exception as e:
logger.error(f"Failed to add allowed role {role_id}: {e}")
raise ConfigError(f"Failed to add allowed role: {str(e)}")
async def remove_allowed_role(
self,
guild_id: int,
role_id: int
) -> None:
async def remove_allowed_role(self, guild_id: int, role_id: int) -> None:
"""Remove a role from allowed roles
Args:
@@ -103,18 +89,13 @@ class RoleManager:
"""
try:
await self.config_manager.remove_from_list(
guild_id,
"allowed_roles",
role_id
guild_id, "allowed_roles", role_id
)
except Exception as e:
logger.error(f"Failed to remove allowed role {role_id}: {e}")
raise ConfigError(f"Failed to remove allowed role: {str(e)}")
async def get_allowed_roles(
self,
guild: discord.Guild
) -> List[discord.Role]:
async def get_allowed_roles(self, guild: discord.Guild) -> List[discord.Role]:
"""Get all allowed roles for a guild
Args:
@@ -152,9 +133,7 @@ class RoleManager:
raise ConfigError(f"Failed to get allowed roles: {str(e)}")
async def verify_role_hierarchy(
self,
guild: discord.Guild,
role: discord.Role
self, guild: discord.Guild, role: discord.Role
) -> Tuple[bool, Optional[str]]:
"""Verify bot's role hierarchy position for managing a role
@@ -170,7 +149,10 @@ class RoleManager:
bot_top_role = bot_member.top_role
if role >= bot_top_role:
return False, f"Role {role.name} is higher than or equal to bot's highest role"
return (
False,
f"Role {role.name} is higher than or equal to bot's highest role",
)
return True, None
@@ -179,9 +161,7 @@ class RoleManager:
return False, "Failed to check role hierarchy"
async def _get_role_names(
self,
guild: discord.Guild,
role_ids: Set[int]
self, guild: discord.Guild, role_ids: Set[int]
) -> List[str]:
"""Get role names from role IDs
@@ -199,11 +179,7 @@ class RoleManager:
role_names.append(role.name)
return role_names
async def _remove_invalid_roles(
self,
guild_id: int,
role_ids: List[int]
) -> None:
async def _remove_invalid_roles(self, guild_id: int, role_ids: List[int]) -> None:
"""Remove invalid roles from allowed roles
Args:
@@ -216,10 +192,7 @@ class RoleManager:
except Exception as e:
logger.error(f"Error removing invalid roles: {e}")
async def get_role_info(
self,
guild: discord.Guild
) -> Dict[str, Any]:
async def get_role_info(self, guild: discord.Guild) -> Dict[str, Any]:
"""Get role configuration information
Args:
@@ -233,16 +206,16 @@ class RoleManager:
bot_member = guild.me
return {
'allowed_roles': allowed_roles,
'bot_top_role': bot_member.top_role,
'bot_permissions': bot_member.guild_permissions,
'role_count': len(allowed_roles)
"allowed_roles": allowed_roles,
"bot_top_role": bot_member.top_role,
"bot_permissions": bot_member.guild_permissions,
"role_count": len(allowed_roles),
}
except Exception as e:
logger.error(f"Error getting role info: {e}")
return {
'allowed_roles': [],
'bot_top_role': None,
'bot_permissions': None,
'role_count': 0
"allowed_roles": [],
"bot_top_role": None,
"bot_permissions": None,
"role_count": 0,
}

View File

@@ -5,10 +5,11 @@ from typing import Dict, Any, List
from datetime import datetime
import discord # type: ignore
try:
# try:
# Try relative imports first
from .exceptions import ConfigurationError as ConfigError
except ImportError:
# except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.config.exceptions import ConfigurationError as ConfigError
@@ -22,9 +23,7 @@ class SettingsFormatter:
self.embed_color = discord.Color.blue()
async def format_settings_embed(
self,
guild: discord.Guild,
settings: Dict[str, Any]
self, guild: discord.Guild, settings: Dict[str, Any]
) -> discord.Embed:
"""Format guild settings into a Discord embed
@@ -42,7 +41,7 @@ class SettingsFormatter:
embed = discord.Embed(
title="Video Archiver Settings",
color=self.embed_color,
timestamp=datetime.utcnow()
timestamp=datetime.utcnow(),
)
# Add sections
@@ -61,27 +60,23 @@ class SettingsFormatter:
raise ConfigError(f"Failed to format settings: {str(e)}")
async def _add_core_settings(
self,
embed: discord.Embed,
guild: discord.Guild,
settings: Dict[str, Any]
self, embed: discord.Embed, guild: discord.Guild, settings: Dict[str, Any]
) -> None:
"""Add core settings to embed"""
embed.add_field(
name="Core Settings",
value="\n".join([
value="\n".join(
[
f"**Enabled:** {settings['enabled']}",
f"**Database Enabled:** {settings['use_database']}",
f"**Update Check Disabled:** {settings['disable_update_check']}"
]),
inline=False
f"**Update Check Disabled:** {settings['disable_update_check']}",
]
),
inline=False,
)
async def _add_channel_settings(
self,
embed: discord.Embed,
guild: discord.Guild,
settings: Dict[str, Any]
self, embed: discord.Embed, guild: discord.Guild, settings: Dict[str, Any]
) -> None:
"""Add channel settings to embed"""
# Get channels with error handling
@@ -89,20 +84,19 @@ class SettingsFormatter:
embed.add_field(
name="Channel Settings",
value="\n".join([
value="\n".join(
[
f"**Archive Channel:** {channels['archive']}",
f"**Notification Channel:** {channels['notification']}",
f"**Log Channel:** {channels['log']}",
f"**Monitored Channels:**\n{channels['monitored']}"
]),
inline=False
f"**Monitored Channels:**\n{channels['monitored']}",
]
),
inline=False,
)
async def _add_permission_settings(
self,
embed: discord.Embed,
guild: discord.Guild,
settings: Dict[str, Any]
self, embed: discord.Embed, guild: discord.Guild, settings: Dict[str, Any]
) -> None:
"""Add permission settings to embed"""
allowed_roles = await self._get_role_names(guild, settings["allowed_roles"])
@@ -110,62 +104,54 @@ class SettingsFormatter:
embed.add_field(
name="Permission Settings",
value=f"**Allowed Roles:**\n{allowed_roles}",
inline=False
inline=False,
)
async def _add_video_settings(
self,
embed: discord.Embed,
settings: Dict[str, Any]
self, embed: discord.Embed, settings: Dict[str, Any]
) -> None:
"""Add video settings to embed"""
embed.add_field(
name="Video Settings",
value="\n".join([
value="\n".join(
[
f"**Format:** {settings['video_format']}",
f"**Max Quality:** {settings['video_quality']}p",
f"**Max File Size:** {settings['max_file_size']}MB"
]),
inline=False
f"**Max File Size:** {settings['max_file_size']}MB",
]
),
inline=False,
)
async def _add_operation_settings(
self,
embed: discord.Embed,
settings: Dict[str, Any]
self, embed: discord.Embed, settings: Dict[str, Any]
) -> None:
"""Add operation settings to embed"""
embed.add_field(
name="Operation Settings",
value="\n".join([
value="\n".join(
[
f"**Delete After Repost:** {settings['delete_after_repost']}",
f"**Message Duration:** {settings['message_duration']} hours",
f"**Concurrent Downloads:** {settings['concurrent_downloads']}",
f"**Max Retries:** {settings['max_retries']}",
f"**Retry Delay:** {settings['retry_delay']}s"
]),
inline=False
f"**Retry Delay:** {settings['retry_delay']}s",
]
),
inline=False,
)
async def _add_site_settings(
self,
embed: discord.Embed,
settings: Dict[str, Any]
self, embed: discord.Embed, settings: Dict[str, Any]
) -> None:
"""Add site settings to embed"""
enabled_sites = settings["enabled_sites"]
sites_text = ", ".join(enabled_sites) if enabled_sites else "All sites"
embed.add_field(
name="Enabled Sites",
value=sites_text,
inline=False
)
embed.add_field(name="Enabled Sites", value=sites_text, inline=False)
async def _get_channel_mentions(
self,
guild: discord.Guild,
settings: Dict[str, Any]
self, guild: discord.Guild, settings: Dict[str, Any]
) -> Dict[str, str]:
"""Get channel mentions with error handling"""
try:
@@ -183,9 +169,17 @@ class SettingsFormatter:
return {
"archive": archive_channel.mention if archive_channel else "Not set",
"notification": notification_channel.mention if notification_channel else "Same as archive",
"notification": (
notification_channel.mention
if notification_channel
else "Same as archive"
),
"log": log_channel.mention if log_channel else "Not set",
"monitored": "\n".join(monitored_channels) if monitored_channels else "All channels"
"monitored": (
"\n".join(monitored_channels)
if monitored_channels
else "All channels"
),
}
except Exception as e:
@@ -194,14 +188,10 @@ class SettingsFormatter:
"archive": "Error",
"notification": "Error",
"log": "Error",
"monitored": "Error getting channels"
"monitored": "Error getting channels",
}
async def _get_role_names(
self,
guild: discord.Guild,
role_ids: List[int]
) -> str:
async def _get_role_names(self, guild: discord.Guild, role_ids: List[int]) -> str:
"""Get role names with error handling"""
try:
role_names = []
@@ -210,7 +200,9 @@ class SettingsFormatter:
if role:
role_names.append(role.name)
return ", ".join(role_names) if role_names else "All roles (no restrictions)"
return (
", ".join(role_names) if role_names else "All roles (no restrictions)"
)
except Exception as e:
logger.error(f"Error getting role names: {e}")

View File

@@ -3,10 +3,11 @@
import logging
from typing import Any, Dict, List, Union
try:
# try:
# Try relative imports first
from .exceptions import ConfigurationError as ConfigError
except ImportError:
# except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.config.exceptions import ConfigurationError as ConfigError
@@ -72,7 +73,9 @@ class ValidationManager:
def _validate_concurrent_downloads(self, value: int) -> None:
"""Validate concurrent downloads setting"""
if not isinstance(value, int) or not (1 <= value <= self.MAX_CONCURRENT_DOWNLOADS):
if not isinstance(value, int) or not (
1 <= value <= self.MAX_CONCURRENT_DOWNLOADS
):
raise ConfigError(
f"Concurrent downloads must be between 1 and {self.MAX_CONCURRENT_DOWNLOADS}"
)
@@ -87,9 +90,7 @@ class ValidationManager:
def _validate_max_retries(self, value: int) -> None:
"""Validate max retries setting"""
if not isinstance(value, int) or not (0 <= value <= self.MAX_RETRIES):
raise ConfigError(
f"Max retries must be between 0 and {self.MAX_RETRIES}"
)
raise ConfigError(f"Max retries must be between 0 and {self.MAX_RETRIES}")
def _validate_retry_delay(self, value: int) -> None:
"""Validate retry delay setting"""
@@ -124,7 +125,12 @@ class ValidationManager:
if setting.endswith("_channel") and value is not None:
if not isinstance(value, int):
raise ConfigError(f"{setting} must be a channel ID (int) or None")
elif setting in ["enabled", "delete_after_repost", "disable_update_check", "use_database"]:
elif setting in [
"enabled",
"delete_after_repost",
"disable_update_check",
"use_database",
]:
self._validate_boolean(value)
elif setting in ["monitored_channels", "allowed_roles", "enabled_sites"]:
self._validate_list(value)

View File

@@ -6,14 +6,15 @@ from typing import Dict, Any, Optional, List, Union
import discord # type: ignore
from redbot.core import Config # type: ignore
try:
# try:
# Try relative imports first
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
except ImportError:
# except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.config.validation_manager import ValidationManager
# from videoarchiver.config.settings_formatter import SettingsFormatter
@@ -80,12 +81,7 @@ class ConfigManager:
logger.error(f"Failed to get guild settings for {guild_id}: {e}")
raise ConfigError(f"Failed to get guild settings: {str(e)}")
async def update_setting(
self,
guild_id: int,
setting: str,
value: Any
) -> None:
async def update_setting(self, guild_id: int, setting: str, value: Any) -> None:
"""Update a specific setting for a guild"""
try:
if setting not in self.default_guild:
@@ -98,14 +94,12 @@ class ConfigManager:
await self.config.guild_from_id(guild_id).set_raw(setting, value=value)
except Exception as e:
logger.error(f"Failed to update setting {setting} for guild {guild_id}: {e}")
logger.error(
f"Failed to update setting {setting} for guild {guild_id}: {e}"
)
raise ConfigError(f"Failed to update setting: {str(e)}")
async def get_setting(
self,
guild_id: int,
setting: str
) -> Any:
async def get_setting(self, guild_id: int, setting: str) -> Any:
"""Get a specific setting for a guild"""
try:
if setting not in self.default_guild:
@@ -118,11 +112,7 @@ class ConfigManager:
logger.error(f"Failed to get setting {setting} for guild {guild_id}: {e}")
raise ConfigError(f"Failed to get setting: {str(e)}")
async def toggle_setting(
self,
guild_id: int,
setting: str
) -> bool:
async def toggle_setting(self, guild_id: int, setting: str) -> bool:
"""Toggle a boolean setting for a guild"""
try:
if setting not in self.default_guild:
@@ -137,22 +127,21 @@ class ConfigManager:
return not current
except Exception as e:
logger.error(f"Failed to toggle setting {setting} for guild {guild_id}: {e}")
logger.error(
f"Failed to toggle setting {setting} for guild {guild_id}: {e}"
)
raise ConfigError(f"Failed to toggle setting: {str(e)}")
async def add_to_list(
self,
guild_id: int,
setting: str,
value: Any
) -> None:
async def add_to_list(self, guild_id: int, setting: str, value: Any) -> None:
"""Add a value to a list setting"""
try:
if setting not in self.default_guild:
raise ConfigError(f"Invalid setting: {setting}")
async with await self._get_guild_lock(guild_id):
async with self.config.guild_from_id(guild_id).get_attr(setting)() as items:
async with self.config.guild_from_id(guild_id).get_attr(
setting
)() as items:
if not isinstance(items, list):
raise ConfigError(f"Setting {setting} is not a list")
if value not in items:
@@ -162,26 +151,25 @@ class ConfigManager:
logger.error(f"Failed to add to list {setting} for guild {guild_id}: {e}")
raise ConfigError(f"Failed to add to list: {str(e)}")
async def remove_from_list(
self,
guild_id: int,
setting: str,
value: Any
) -> None:
async def remove_from_list(self, guild_id: int, setting: str, value: Any) -> None:
"""Remove a value from a list setting"""
try:
if setting not in self.default_guild:
raise ConfigError(f"Invalid setting: {setting}")
async with await self._get_guild_lock(guild_id):
async with self.config.guild_from_id(guild_id).get_attr(setting)() as items:
async with self.config.guild_from_id(guild_id).get_attr(
setting
)() as items:
if not isinstance(items, list):
raise ConfigError(f"Setting {setting} is not a list")
if value in items:
items.remove(value)
except Exception as e:
logger.error(f"Failed to remove from list {setting} for guild {guild_id}: {e}")
logger.error(
f"Failed to remove from list {setting} for guild {guild_id}: {e}"
)
raise ConfigError(f"Failed to remove from list: {str(e)}")
async def format_settings_embed(self, guild: discord.Guild) -> discord.Embed:
@@ -194,11 +182,15 @@ class ConfigManager:
raise ConfigError(f"Failed to format settings: {str(e)}")
# Channel management delegated to channel_manager
async def get_channel(self, guild: discord.Guild, channel_type: str) -> Optional[discord.TextChannel]:
async def get_channel(
self, guild: discord.Guild, channel_type: str
) -> Optional[discord.TextChannel]:
"""Get a channel by type"""
return await self.channel_manager.get_channel(guild, channel_type)
async def get_monitored_channels(self, guild: discord.Guild) -> List[discord.TextChannel]:
async def get_monitored_channels(
self, guild: discord.Guild
) -> List[discord.TextChannel]:
"""Get all monitored channels for a guild"""
return await self.channel_manager.get_monitored_channels(guild)

View File

@@ -1,9 +1,10 @@
"""Core module for VideoArchiver cog"""
try:
# try:
# Try relative imports first
from .base import VideoArchiver
except ImportError:
# except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.core.base import VideoArchiver

View File

@@ -12,7 +12,7 @@ import discord # type: ignore
from redbot.core.bot import Red # type: ignore
from redbot.core.commands import GroupCog, Context # type: ignore
try:
# try:
# Try relative imports first
from .settings import Settings
from .lifecycle import LifecycleManager, LifecycleState
@@ -29,7 +29,8 @@ try:
from ..database.video_archive_db import VideoArchiveDB
from ..config_manager import ConfigManager
from ..utils.exceptions import CogError, ErrorContext, ErrorSeverity
except ImportError:
# except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.core.settings import Settings
# from videoarchiver.core.lifecycle import LifecycleManager, LifecycleState

View File

@@ -8,19 +8,19 @@ from enum import Enum, auto
from pathlib import Path
from typing import TYPE_CHECKING, Dict, Any, Optional, TypedDict, ClassVar
try:
#try:
# Try relative imports first
from ..utils.file_ops import cleanup_downloads
from ..utils.exceptions import CleanupError, ErrorContext, ErrorSeverity
except ImportError:
#except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.utils.file_ops import cleanup_downloads
# from videoarchiver.utils.exceptions import CleanupError, ErrorContext, ErrorSeverity
if TYPE_CHECKING:
try:
#try:
from .base import VideoArchiver
except ImportError:
#except ImportError:
# from videoarchiver.core.base import VideoArchiver
logger = logging.getLogger("VideoArchiver")

View File

@@ -6,9 +6,9 @@
from typing import TYPE_CHECKING
if TYPE_CHECKING:
try:
# try:
from .base import VideoArchiver
except ImportError:
# except ImportError:
# from videoarchiver.core.base import VideoArchiver
def setup_commands(cog: "VideoArchiver") -> None:

View File

@@ -20,7 +20,7 @@ from datetime import datetime
from pathlib import Path
import importlib
try:
# try:
# Try relative imports first
from ..utils.exceptions import ComponentError, ErrorContext, ErrorSeverity
from ..utils.path_manager import PathManager
@@ -28,7 +28,8 @@ try:
from ..processor.core import VideoProcessor
from ..queue.manager import EnhancedVideoQueueManager
from ..ffmpeg.ffmpeg_manager import FFmpegManager
except ImportError:
# except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.utils.exceptions import ComponentError, ErrorContext, ErrorSeverity
# from videoarchiver.utils.path_manager import PathManager

View File

@@ -14,7 +14,7 @@ from redbot.core.commands import ( # type: ignore
CommandError
)
try:
#try:
# Try relative imports first
from ..utils.exceptions import (
VideoArchiverError,
@@ -36,27 +36,27 @@ try:
ConfigurationError
)
from ..core.response_handler import response_manager
except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.utils.exceptions import (
VideoArchiverError,
ErrorSeverity,
ErrorContext,
ProcessorError,
ValidationError,
DisplayError,
URLExtractionError,
MessageHandlerError,
QueueHandlerError,
QueueProcessorError,
FFmpegError,
DatabaseError,
HealthCheckError,
TrackingError,
NetworkError,
ResourceExhaustedError,
ConfigurationError
)
# except ImportError:
# # Fall back to absolute imports if relative imports fail
# # from videoarchiver.utils.exceptions import (
# VideoArchiverError,
# ErrorSeverity,
# ErrorContext,
# ProcessorError,
# ValidationError,
# DisplayError,
# URLExtractionError,
# MessageHandlerError,
# QueueHandlerError,
# QueueProcessorError,
# FFmpegError,
# DatabaseError,
# HealthCheckError,
# TrackingError,
# NetworkError,
# ResourceExhaustedError,
# ConfigurationError
# )
# from videoarchiver.core.response_handler import response_manager
logger = logging.getLogger("VideoArchiver")

View File

@@ -9,7 +9,7 @@ from typing import TYPE_CHECKING, Dict, Any, Optional, TypedDict, ClassVar, List
import discord # type: ignore
try:
#try:
# Try relative imports first
from ..processor.constants import REACTIONS
from ..processor.reactions import handle_archived_reaction
@@ -17,7 +17,7 @@ try:
from .error_handler import ErrorManager
from .response_handler import response_manager
from ..utils.exceptions import EventError, ErrorContext, ErrorSeverity
except ImportError:
#except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.processor.constants import REACTIONS
# from videoarchiver.processor.reactions import handle_archived_reaction
@@ -27,9 +27,9 @@ except ImportError:
# from videoarchiver.utils.exceptions import EventError, ErrorContext, ErrorSeverity
if TYPE_CHECKING:
try:
#try:
from .base import VideoArchiver
except ImportError:
# except ImportError:
# from videoarchiver.core.base import VideoArchiver
logger = logging.getLogger("VideoArchiver")

View File

@@ -4,13 +4,14 @@ import logging
from pathlib import Path
from typing import TYPE_CHECKING, Dict, Any, Optional
try:
# try:
# Try relative imports first
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
except ImportError:
# except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.utils.download_core import DownloadCore
# from videoarchiver.utils.message_manager import MessageManager
@@ -18,9 +19,9 @@ except ImportError:
# from videoarchiver.utils.exceptions import VideoArchiverError as ProcessingError
if TYPE_CHECKING:
try:
# try:
from .base import VideoArchiver
except ImportError:
# except ImportError:
# from videoarchiver.core.base import VideoArchiver
logger = logging.getLogger("VideoArchiver")

View File

@@ -4,19 +4,20 @@ from typing import TYPE_CHECKING, Optional, Dict, Any
import asyncio
import logging
try:
# try:
# Try relative imports first
from ..utils.exceptions import ComponentError, ErrorContext, ErrorSeverity
from .lifecycle import LifecycleState
except ImportError:
# except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.utils.exceptions import ComponentError, ErrorContext, ErrorSeverity
# from videoarchiver.core.lifecycle import LifecycleState
if TYPE_CHECKING:
try:
# try:
from .base import VideoArchiver
except ImportError:
# except ImportError:
# from videoarchiver.core.base import VideoArchiver
logger = logging.getLogger("VideoArchiver")
@@ -48,8 +49,8 @@ async def initialize_cog(cog: "VideoArchiver") -> None:
"Initialization",
"initialize_cog",
{"state": cog.lifecycle_manager.state_tracker.state.name},
ErrorSeverity.HIGH
)
ErrorSeverity.HIGH,
),
)
@@ -103,8 +104,8 @@ def get_init_status(cog: "VideoArchiver") -> Dict[str, Any]:
"update_checker",
"ffmpeg_mgr",
"components",
"db"
"db",
]
),
"history": cog.lifecycle_manager.state_tracker.get_state_history()
"history": cog.lifecycle_manager.state_tracker.get_state_history(),
}

View File

@@ -7,7 +7,7 @@ from typing import Optional, Dict, Any, Set, List, Callable, TypedDict, ClassVar
from enum import Enum, auto
from datetime import datetime
try:
# try:
# Try relative imports first
from .cleanup import cleanup_resources, force_cleanup_resources
from ..utils.exceptions import (
@@ -17,16 +17,16 @@ try:
ComponentError,
CleanupError,
)
except ImportError:
#except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.core.cleanup import cleanup_resources, force_cleanup_resources
# from videoarchiver.utils.exceptions import (
VideoArchiverError,
ErrorContext,
ErrorSeverity,
ComponentError,
CleanupError,
)
# VideoArchiverError,
# ErrorContext,
# ErrorSeverity,
# ComponentError,
# CleanupError,
# )
logger = logging.getLogger("VideoArchiver")

View File

@@ -7,10 +7,11 @@ from datetime import datetime
import discord # type: ignore
from redbot.core.commands import Context # type: ignore
try:
# try:
# Try relative imports first
from ..utils.exceptions import ErrorSeverity
except ImportError:
# except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.utils.exceptions import ErrorSeverity

View File

@@ -4,29 +4,35 @@ from typing import Dict, Any, List, Optional, Union, TypedDict, ClassVar
from dataclasses import dataclass, field
from enum import Enum, auto
try:
# try:
# Try relative imports first
from ..utils.exceptions import ConfigurationError, ErrorContext, ErrorSeverity
except ImportError:
# except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.utils.exceptions import ConfigurationError, ErrorContext, ErrorSeverity
class VideoFormat(Enum):
"""Supported video formats"""
MP4 = "mp4"
WEBM = "webm"
MKV = "mkv"
class VideoQuality(Enum):
"""Video quality presets"""
LOW = "low" # 480p
MEDIUM = "medium" # 720p
HIGH = "high" # 1080p
ULTRA = "ultra" # 4K
class SettingCategory(Enum):
"""Setting categories"""
GENERAL = auto()
CHANNELS = auto()
PERMISSIONS = auto()
@@ -35,15 +41,19 @@ class SettingCategory(Enum):
PERFORMANCE = auto()
FEATURES = auto()
class ValidationResult(TypedDict):
"""Type definition for validation result"""
valid: bool
error: Optional[str]
details: Dict[str, Any]
@dataclass
class SettingDefinition:
"""Defines a setting's properties"""
name: str
category: SettingCategory
default_value: Any
@@ -66,8 +76,8 @@ class SettingDefinition:
"Settings",
"definition_validation",
{"setting": self.name},
ErrorSeverity.HIGH
)
ErrorSeverity.HIGH,
),
)
if self.min_value is not None and self.max_value is not None:
@@ -78,10 +88,11 @@ class SettingDefinition:
"Settings",
"definition_validation",
{"setting": self.name},
ErrorSeverity.HIGH
)
ErrorSeverity.HIGH,
),
)
class Settings:
"""Manages VideoArchiver settings"""
@@ -92,7 +103,7 @@ class Settings:
category=SettingCategory.GENERAL,
default_value=False,
description="Whether the archiver is enabled for this guild",
data_type=bool
data_type=bool,
),
"archive_channel": SettingDefinition(
name="archive_channel",
@@ -101,7 +112,7 @@ class Settings:
description="Channel where archived videos are posted",
data_type=int,
required=False,
error_message="Archive channel must be a valid channel ID"
error_message="Archive channel must be a valid channel ID",
),
"log_channel": SettingDefinition(
name="log_channel",
@@ -110,7 +121,7 @@ class Settings:
description="Channel for logging archiver actions",
data_type=int,
required=False,
error_message="Log channel must be a valid channel ID"
error_message="Log channel must be a valid channel ID",
),
"enabled_channels": SettingDefinition(
name="enabled_channels",
@@ -118,7 +129,7 @@ class Settings:
default_value=[],
description="Channels to monitor (empty means all channels)",
data_type=list,
error_message="Enabled channels must be a list of valid channel IDs"
error_message="Enabled channels must be a list of valid channel IDs",
),
"allowed_roles": SettingDefinition(
name="allowed_roles",
@@ -126,7 +137,7 @@ class Settings:
default_value=[],
description="Roles allowed to use archiver (empty means all roles)",
data_type=list,
error_message="Allowed roles must be a list of valid role IDs"
error_message="Allowed roles must be a list of valid role IDs",
),
"video_format": SettingDefinition(
name="video_format",
@@ -135,7 +146,7 @@ class Settings:
description="Format for archived videos",
data_type=str,
choices=[format.value for format in VideoFormat],
error_message=f"Video format must be one of: {', '.join(f.value for f in VideoFormat)}"
error_message=f"Video format must be one of: {', '.join(f.value for f in VideoFormat)}",
),
"video_quality": SettingDefinition(
name="video_quality",
@@ -144,7 +155,7 @@ class Settings:
description="Quality preset for archived videos",
data_type=str,
choices=[quality.value for quality in VideoQuality],
error_message=f"Video quality must be one of: {', '.join(q.value for q in VideoQuality)}"
error_message=f"Video quality must be one of: {', '.join(q.value for q in VideoQuality)}",
),
"max_file_size": SettingDefinition(
name="max_file_size",
@@ -154,7 +165,7 @@ class Settings:
data_type=int,
min_value=1,
max_value=100,
error_message="Max file size must be between 1 and 100 MB"
error_message="Max file size must be between 1 and 100 MB",
),
"message_duration": SettingDefinition(
name="message_duration",
@@ -164,7 +175,7 @@ class Settings:
data_type=int,
min_value=5,
max_value=300,
error_message="Message duration must be between 5 and 300 seconds"
error_message="Message duration must be between 5 and 300 seconds",
),
"message_template": SettingDefinition(
name="message_template",
@@ -172,7 +183,7 @@ class Settings:
default_value="{author} archived a video from {channel}",
description="Template for archive messages",
data_type=str,
error_message="Message template must contain {author} and {channel} placeholders"
error_message="Message template must contain {author} and {channel} placeholders",
),
"concurrent_downloads": SettingDefinition(
name="concurrent_downloads",
@@ -182,7 +193,7 @@ class Settings:
data_type=int,
min_value=1,
max_value=5,
error_message="Concurrent downloads must be between 1 and 5"
error_message="Concurrent downloads must be between 1 and 5",
),
"enabled_sites": SettingDefinition(
name="enabled_sites",
@@ -191,14 +202,14 @@ class Settings:
description="Sites to enable archiving for (None means all sites)",
data_type=list,
required=False,
error_message="Enabled sites must be a list of valid site identifiers"
error_message="Enabled sites must be a list of valid site identifiers",
),
"use_database": SettingDefinition(
name="use_database",
category=SettingCategory.FEATURES,
default_value=False,
description="Enable database tracking of archived videos",
data_type=bool
data_type=bool,
),
}
@@ -216,7 +227,9 @@ class Settings:
return cls.SETTINGS.get(setting)
@classmethod
def get_settings_by_category(cls, category: SettingCategory) -> Dict[str, SettingDefinition]:
def get_settings_by_category(
cls, category: SettingCategory
) -> Dict[str, SettingDefinition]:
"""
Get all settings in a category.
@@ -252,18 +265,15 @@ class Settings:
raise ConfigurationError(
f"Unknown setting: {setting}",
context=ErrorContext(
"Settings",
"validation",
{"setting": setting},
ErrorSeverity.HIGH
)
"Settings", "validation", {"setting": setting}, ErrorSeverity.HIGH
),
)
details = {
"setting": setting,
"value": value,
"type": type(value).__name__,
"expected_type": definition.data_type.__name__
"expected_type": definition.data_type.__name__,
}
# Check type
@@ -271,15 +281,13 @@ class Settings:
return ValidationResult(
valid=False,
error=f"Invalid type: expected {definition.data_type.__name__}, got {type(value).__name__}",
details=details
details=details,
)
# Check required
if definition.required and value is None:
return ValidationResult(
valid=False,
error="Required setting cannot be None",
details=details
valid=False, error="Required setting cannot be None", details=details
)
# Check choices
@@ -287,7 +295,7 @@ class Settings:
return ValidationResult(
valid=False,
error=f"Value must be one of: {', '.join(map(str, definition.choices))}",
details=details
details=details,
)
# Check numeric bounds
@@ -296,13 +304,13 @@ class Settings:
return ValidationResult(
valid=False,
error=f"Value must be at least {definition.min_value}",
details=details
details=details,
)
if definition.max_value is not None and value > definition.max_value:
return ValidationResult(
valid=False,
error=f"Value must be at most {definition.max_value}",
details=details
details=details,
)
# Custom validation
@@ -313,20 +321,12 @@ class Settings:
return ValidationResult(
valid=False,
error=definition.error_message or "Validation failed",
details=details
details=details,
)
except Exception as e:
return ValidationResult(
valid=False,
error=str(e),
details=details
)
return ValidationResult(valid=False, error=str(e), details=details)
return ValidationResult(
valid=True,
error=None,
details=details
)
return ValidationResult(valid=True, error=None, details=details)
@property
def default_guild_settings(self) -> Dict[str, Any]:
@@ -337,8 +337,7 @@ class Settings:
Dictionary of default settings
"""
return {
name: definition.default_value
for name, definition in self.SETTINGS.items()
name: definition.default_value for name, definition in self.SETTINGS.items()
}
@classmethod
@@ -362,7 +361,7 @@ class Settings:
f"Description: {definition.description}",
f"Type: {definition.data_type.__name__}",
f"Required: {definition.required}",
f"Default: {definition.default_value}"
f"Default: {definition.default_value}",
]
if definition.choices:

View File

@@ -1,12 +1,13 @@
"""Database management package for video archiving"""
try:
# try:
# Try relative imports first
from .connection_manager import DatabaseConnectionManager
from .query_manager import DatabaseQueryManager
from .schema_manager import DatabaseSchemaManager
from .video_archive_db import VideoArchiveDB
except ImportError:
# except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.database.connection_manager import DatabaseConnectionManager
# from videoarchiver.database.query_manager import DatabaseQueryManager
@@ -14,8 +15,8 @@ except ImportError:
# from videoarchiver.database.video_archive_db import VideoArchiveDB
__all__ = [
'DatabaseConnectionManager',
'DatabaseQueryManager',
'DatabaseSchemaManager',
'VideoArchiveDB'
"DatabaseConnectionManager",
"DatabaseQueryManager",
"DatabaseSchemaManager",
"VideoArchiveDB",
]

View File

@@ -10,10 +10,10 @@ import threading
from queue import Queue, Empty
from datetime import datetime
try:
#try:
# Try relative imports first
from ..utils.exceptions import DatabaseError, ErrorContext, ErrorSeverity
except ImportError:
#except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.utils.exceptions import DatabaseError, ErrorContext, ErrorSeverity

View File

@@ -7,10 +7,10 @@ from typing import List, Dict, Any, Optional, TypedDict, ClassVar, Union
from enum import Enum, auto
from datetime import datetime
try:
#try:
# Try relative imports first
from ..utils.exceptions import DatabaseError, ErrorContext, ErrorSeverity
except ImportError:
#except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.utils.exceptions import DatabaseError, ErrorContext, ErrorSeverity

View File

@@ -4,12 +4,13 @@ import logging
from pathlib import Path
from typing import Optional, Dict, Any, List
try:
# try:
# Try relative imports first
from .schema_manager import DatabaseSchemaManager
from .query_manager import DatabaseQueryManager
from .connection_manager import DatabaseConnectionManager
except ImportError:
# except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.database.schema_manager import DatabaseSchemaManager
# from videoarchiver.database.query_manager import DatabaseQueryManager

View File

@@ -18,7 +18,7 @@ logging.basicConfig(
logger = logging.getLogger("VideoArchiver")
# Import components after logging is configured
try:
#try:
# Try relative imports first
from .ffmpeg_manager import FFmpegManager
from .video_analyzer import VideoAnalyzer
@@ -44,7 +44,7 @@ try:
AudioError,
BitrateError,
)
except ImportError:
#except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.ffmpeg.ffmpeg_manager import FFmpegManager
# from videoarchiver.ffmpeg.video_analyzer import VideoAnalyzer
@@ -52,24 +52,24 @@ except ImportError:
# from videoarchiver.ffmpeg.encoder_params import EncoderParams
# from videoarchiver.ffmpeg.ffmpeg_downloader import FFmpegDownloader
# from videoarchiver.ffmpeg.exceptions import (
FFmpegError,
DownloadError,
VerificationError,
EncodingError,
AnalysisError,
GPUError,
HardwareAccelerationError,
FFmpegNotFoundError,
FFprobeError,
CompressionError,
FormatError,
PermissionError,
TimeoutError,
ResourceError,
QualityError,
AudioError,
BitrateError,
)
# FFmpegError,
# DownloadError,
# VerificationError,
# EncodingError,
# AnalysisError,
# GPUError,
# HardwareAccelerationError,
# FFmpegNotFoundError,
# FFprobeError,
# CompressionError,
# FormatError,
# PermissionError,
# TimeoutError,
# ResourceError,
# QualityError,
# AudioError,
# BitrateError,
# )
class FFmpeg:

View File

@@ -5,7 +5,7 @@ import os
from pathlib import Path
from typing import Dict, Optional
try:
#try:
# Try relative imports first
from .exceptions import (
FFmpegError,
@@ -16,15 +16,15 @@ try:
)
from .ffmpeg_downloader import FFmpegDownloader
from .verification_manager import VerificationManager
except ImportError:
#except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.ffmpeg.exceptions import (
FFmpegError,
DownloadError,
VerificationError,
PermissionError,
FFmpegNotFoundError
)
# FFmpegError,
# DownloadError,
# VerificationError,
# PermissionError,
# FFmpegNotFoundError
# )
# from videoarchiver.ffmpeg.ffmpeg_downloader import FFmpegDownloader
# from videoarchiver.ffmpeg.verification_manager import VerificationManager

View File

@@ -4,10 +4,10 @@ import os
import logging
from typing import Dict, Any
try:
#try:
# Try relative imports first
from .exceptions import CompressionError, QualityError, BitrateError
except ImportError:
#except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.ffmpeg.exceptions import CompressionError, QualityError, BitrateError

View File

@@ -16,10 +16,11 @@ from typing import Optional, Dict, List
import time
import lzma
try:
# try:
# Try relative imports first
from .exceptions import DownloadError
except ImportError:
# except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.ffmpeg.exceptions import DownloadError
@@ -249,14 +250,16 @@ class FFmpegDownloader:
binary_files = [
f
for f in zip_ref.namelist()
if f.endswith(f"/bin/{binary_name}") or f.endswith(f"\\bin\\{binary_name}")
if f.endswith(f"/bin/{binary_name}")
or f.endswith(f"\\bin\\{binary_name}")
]
if not binary_files:
# Fallback to old structure
binary_files = [
f
for f in zip_ref.namelist()
if f.endswith(f"/{binary_name}") or f.endswith(f"\\{binary_name}")
if f.endswith(f"/{binary_name}")
or f.endswith(f"\\{binary_name}")
]
if not binary_files:
raise DownloadError(f"{binary_name} not found in archive")
@@ -271,10 +274,10 @@ class FFmpegDownloader:
"""Extract from tar archive (Linux/macOS)"""
try:
# First decompress the .xz file in chunks to prevent blocking
decompressed_path = archive_path.with_suffix('')
decompressed_path = archive_path.with_suffix("")
chunk_size = 1024 * 1024 # 1MB chunks
with lzma.open(archive_path, 'rb') as compressed:
with open(decompressed_path, 'wb') as decompressed:
with lzma.open(archive_path, "rb") as compressed:
with open(decompressed_path, "wb") as decompressed:
while True:
chunk = compressed.read(chunk_size)
if not chunk:
@@ -289,12 +292,16 @@ class FFmpegDownloader:
for binary_name in binary_names:
# BtbN's builds have binaries in bin directory
binary_files = [
f for f in tar_ref.getnames() if f.endswith(f"/bin/{binary_name}")
f
for f in tar_ref.getnames()
if f.endswith(f"/bin/{binary_name}")
]
if not binary_files:
# Fallback to old structure
binary_files = [
f for f in tar_ref.getnames() if f.endswith(f"/{binary_name}")
f
for f in tar_ref.getnames()
if f.endswith(f"/{binary_name}")
]
if not binary_files:
raise DownloadError(f"{binary_name} not found in archive")
@@ -306,7 +313,9 @@ class FFmpegDownloader:
target_path = self.base_dir / binary_name
# Copy file in chunks
with open(extracted_path, 'rb') as src, open(target_path, 'wb') as dst:
with open(extracted_path, "rb") as src, open(
target_path, "wb"
) as dst:
while True:
chunk = src.read(chunk_size)
if not chunk:
@@ -350,7 +359,7 @@ class FFmpegDownloader:
timeout=5,
text=True,
check=False, # Don't raise on non-zero return code
env={"PATH": os.environ.get("PATH", "")} # Ensure PATH is set
env={"PATH": os.environ.get("PATH", "")}, # Ensure PATH is set
)
except subprocess.TimeoutExpired:
logger.error("FFmpeg verification timed out")
@@ -368,7 +377,7 @@ class FFmpegDownloader:
timeout=5,
text=True,
check=False, # Don't raise on non-zero return code
env={"PATH": os.environ.get("PATH", "")} # Ensure PATH is set
env={"PATH": os.environ.get("PATH", "")}, # Ensure PATH is set
)
except subprocess.TimeoutExpired:
logger.error("FFprobe verification timed out")

View File

@@ -6,26 +6,23 @@ import multiprocessing
from pathlib import Path
from typing import Dict, Any, Optional
try:
# try:
# Try relative imports first
from .exceptions import (
FFmpegError,
AnalysisError,
FFmpegNotFoundError
)
from .exceptions import FFmpegError, AnalysisError, FFmpegNotFoundError
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
except ImportError:
# except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.ffmpeg.exceptions import (
FFmpegError,
AnalysisError,
FFmpegNotFoundError
)
# FFmpegError,
# AnalysisError,
# FFmpegNotFoundError
# )
# from videoarchiver.ffmpeg.gpu_detector import GPUDetector
# from videoarchiver.ffmpeg.video_analyzer import VideoAnalyzer
# from videoarchiver.ffmpeg.encoder_params import EncoderParams
@@ -53,7 +50,7 @@ class FFmpegManager:
base_dir=self.base_dir,
system=platform.system(),
machine=platform.machine(),
verification_manager=self.verification_manager
verification_manager=self.verification_manager,
)
# Initialize components
@@ -87,7 +84,9 @@ class FFmpegManager:
raise
raise AnalysisError(f"Failed to analyze video: {e}")
def get_compression_params(self, input_path: str, target_size_mb: int) -> Dict[str, str]:
def get_compression_params(
self, input_path: str, target_size_mb: int
) -> Dict[str, str]:
"""Get optimal compression parameters for the given input file"""
try:
# Analyze video first
@@ -113,7 +112,7 @@ class FFmpegManager:
"preset": "medium",
"crf": "23",
"c:a": "aac",
"b:a": "128k"
"b:a": "128k",
}
def get_ffmpeg_path(self) -> str:

View File

@@ -6,22 +6,23 @@ import subprocess
from pathlib import Path
from typing import Dict, List, Optional
try:
# try:
# Try relative imports first
from .exceptions import (
TimeoutError,
VerificationError,
EncodingError,
handle_ffmpeg_error
handle_ffmpeg_error,
)
except ImportError:
# except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.ffmpeg.exceptions import (
TimeoutError,
VerificationError,
EncodingError,
handle_ffmpeg_error
)
# TimeoutError,
# VerificationError,
# EncodingError,
# handle_ffmpeg_error
# )
logger = logging.getLogger("FFmpegVerification")
@@ -33,10 +34,7 @@ class VerificationManager:
self.process_manager = process_manager
def verify_ffmpeg(
self,
ffmpeg_path: Path,
ffprobe_path: Path,
gpu_info: Dict[str, bool]
self, ffmpeg_path: Path, ffprobe_path: Path, gpu_info: Dict[str, bool]
) -> None:
"""Verify FFmpeg functionality with comprehensive checks
@@ -72,8 +70,7 @@ class VerificationManager:
"""Verify FFmpeg version"""
try:
result = self._execute_command(
[str(ffmpeg_path), "-version"],
"FFmpeg version check"
[str(ffmpeg_path), "-version"], "FFmpeg version check"
)
logger.info(f"FFmpeg version: {result.stdout.split()[2]}")
except Exception as e:
@@ -83,23 +80,20 @@ class VerificationManager:
"""Verify FFprobe version"""
try:
result = self._execute_command(
[str(ffprobe_path), "-version"],
"FFprobe version check"
[str(ffprobe_path), "-version"], "FFprobe version check"
)
logger.info(f"FFprobe version: {result.stdout.split()[2]}")
except Exception as e:
raise VerificationError(f"FFprobe version check failed: {e}")
def _verify_ffmpeg_capabilities(
self,
ffmpeg_path: Path,
gpu_info: Dict[str, bool]
self, ffmpeg_path: Path, gpu_info: Dict[str, bool]
) -> None:
"""Verify FFmpeg capabilities and encoders"""
try:
result = self._execute_command(
[str(ffmpeg_path), "-hide_banner", "-encoders"],
"FFmpeg capabilities check"
"FFmpeg capabilities check",
)
# Verify required encoders
@@ -107,7 +101,8 @@ class VerificationManager:
available_encoders = result.stdout.lower()
missing_encoders = [
encoder for encoder in required_encoders
encoder
for encoder in required_encoders
if encoder not in available_encoders
]
@@ -122,17 +117,12 @@ class VerificationManager:
raise VerificationError(f"FFmpeg capabilities check failed: {e}")
def _execute_command(
self,
command: List[str],
operation: str,
timeout: int = 10
self, command: List[str], operation: str, timeout: int = 10
) -> subprocess.CompletedProcess:
"""Execute a command with proper error handling"""
try:
result = self.process_manager.execute_command(
command,
timeout=timeout,
check=False
command, timeout=timeout, check=False
)
if result.returncode != 0:

View File

@@ -8,10 +8,17 @@ from typing import Any, ClassVar, Dict, List, Optional, Tuple, TYPE_CHECKING
import discord # type: ignore
from discord.ext import commands # type: ignore
# from videoarchiver.core.types import ComponentState, ProcessorState, ComponentStatus, IComponent, IConfigManager, IQueueManager
# from videoarchiver.processor.constants import REACTIONS
# from videoarchiver.utils.progress_tracker import ProgressTracker
# from videoarchiver.utils.exceptions import ProcessorError
from ..core.types import (
ComponentState,
ProcessorState,
ComponentStatus,
IComponent,
IConfigManager,
IQueueManager,
)
from .constants import REACTIONS
from ..utils.progress_tracker import ProgressTracker
from ..utils.exceptions import ProcessorError
logger = logging.getLogger("VideoArchiver")
@@ -45,11 +52,13 @@ class OperationTracker:
) -> None:
"""End tracking an operation"""
if op_id in self.operations:
self.operations[op_id].update({
self.operations[op_id].update(
{
"end_time": datetime.utcnow(),
"status": "success" if success else "error",
"error": error,
})
}
)
# Move to history
self.operation_history.append(self.operations.pop(op_id))
# Update counts
@@ -114,11 +123,13 @@ class HealthMonitor:
self.last_check = datetime.utcnow()
# Check component health
self.health_status.update({
self.health_status.update(
{
"queue_handler": self.processor.queue_handler.is_healthy(),
"message_handler": self.processor.message_handler.is_healthy(),
"progress_tracker": self.progress_tracker.is_healthy(),
})
}
)
# Check operation health
op_stats = self.processor.operation_tracker.get_operation_stats()
@@ -168,8 +179,12 @@ class VideoProcessor(IComponent):
from .cleanup_manager import CleanupManager, CleanupStrategy
# Initialize handlers
self.queue_handler: "QueueHandler" = QueueHandler(bot, config_manager, components)
self.message_handler: "MessageHandler" = MessageHandler(bot, config_manager, queue_manager)
self.queue_handler: "QueueHandler" = QueueHandler(
bot, config_manager, components
)
self.message_handler: "MessageHandler" = MessageHandler(
bot, config_manager, queue_manager
)
self.cleanup_manager: "CleanupManager" = CleanupManager(
self.queue_handler, ffmpeg_mgr, CleanupStrategy.NORMAL
)
@@ -243,9 +258,7 @@ class VideoProcessor(IComponent):
async def cleanup(self) -> None:
"""Clean up resources and stop processing"""
op_id = self.operation_tracker.start_operation(
"cleanup", {"type": "normal"}
)
op_id = self.operation_tracker.start_operation("cleanup", {"type": "normal"})
try:
self._state = ProcessorState.SHUTDOWN
@@ -260,9 +273,7 @@ class VideoProcessor(IComponent):
async def force_cleanup(self) -> None:
"""Force cleanup of resources"""
op_id = self.operation_tracker.start_operation(
"cleanup", {"type": "force"}
)
op_id = self.operation_tracker.start_operation("cleanup", {"type": "force"})
try:
self._state = ProcessorState.SHUTDOWN
@@ -321,5 +332,5 @@ class VideoProcessor(IComponent):
"operations": self.operation_tracker.get_operation_stats(),
"active_operations": self.operation_tracker.get_active_operations(),
"health_status": self.health_monitor.health_status,
}
},
)

View File

@@ -4,12 +4,22 @@ import asyncio
import logging
from datetime import datetime, timedelta
from enum import auto, Enum
from typing import Any, ClassVar, Dict, List, Optional, Set, Tuple, TypedDict, TYPE_CHECKING
from typing import (
Any,
ClassVar,
Dict,
List,
Optional,
Set,
Tuple,
TypedDict,
TYPE_CHECKING,
)
import discord # type: ignore
from discord.ext import commands # type: ignore
try:
# try:
# Try relative imports first
from ..config_manager import ConfigManager
from .constants import REACTIONS
@@ -17,7 +27,8 @@ try:
from .url_extractor import URLExtractor, URLMetadata
from ..queue.types import QueuePriority
from ..utils.exceptions import MessageHandlerError
except ImportError:
# except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.config_manager import ConfigManager
# from videoarchiver.processor.constants import REACTIONS
@@ -27,9 +38,10 @@ except ImportError:
# from videoarchiver.utils.exceptions import MessageHandlerError
if TYPE_CHECKING:
try:
# try:
from ..queue.manager import EnhancedVideoQueueManager
except ImportError:
# except ImportError:
# from videoarchiver.queue.manager import EnhancedVideoQueueManager
logger = logging.getLogger("VideoArchiver")
@@ -337,7 +349,7 @@ class MessageHandler:
channel_id=message.channel.id,
guild_id=message.guild.id,
author_id=message.author.id,
priority=QueuePriority.NORMAL.value
priority=QueuePriority.NORMAL.value,
)
except Exception as e:
raise MessageHandlerError(f"Queue processing failed: {str(e)}")

View File

@@ -7,10 +7,10 @@ from typing import Dict, Optional, Tuple, List, Any, Callable, Set, TypedDict, C
from datetime import datetime
import discord # type: ignore
try:
#try:
# Try relative imports first
from ..utils.exceptions import ValidationError
except ImportError:
#except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.utils.exceptions import ValidationError

View File

@@ -8,7 +8,7 @@ from typing import Optional, Dict, Any, List, Tuple, Set, TypedDict, ClassVar, C
from datetime import datetime
import discord # type: ignore
try:
# try:
# Try relative imports first
from .. import utils
from ..database.video_archive_db import VideoArchiveDB
@@ -19,7 +19,8 @@ try:
from ..config_manager import ConfigManager
from . import progress_tracker # Import from processor package
from .constants import REACTIONS
except ImportError:
# except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.database.video_archive_db import VideoArchiveDB
# from videoarchiver.utils.download_manager import DownloadManager

View File

@@ -5,11 +5,11 @@ import asyncio
from typing import List, Optional, Dict, Any, Set, ClassVar
from datetime import datetime
try:
#try:
# Try relative imports first
from ..queue.types import QueuePriority, QueueMetrics, ProcessingMetrics
from ..queue.models import QueueItem
except ImportError:
#except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.queue.types import QueuePriority, QueueMetrics, ProcessingMetrics
# from videoarchiver.queue.models import QueueItem

View File

@@ -7,7 +7,7 @@ from typing import List, Optional
import discord # type: ignore
from urllib.parse import urlparse
try:
# try:
# Try relative imports first
from ..processor.constants import (
REACTIONS,
@@ -16,14 +16,15 @@ try:
get_progress_emoji,
)
from ..database.video_archive_db import VideoArchiveDB
except ImportError:
# except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.processor.constants import (
REACTIONS,
ReactionType,
get_reaction,
get_progress_emoji,
)
# REACTIONS,
# ReactionType,
# get_reaction,
# get_progress_emoji,
# )
# from videoarchiver.database.video_archive_db import VideoArchiveDB
logger = logging.getLogger("VideoArchiver")

View File

@@ -18,10 +18,11 @@ from typing import (
)
import discord # type: ignore
try:
# try:
# Try relative imports first
from ..utils.exceptions import DisplayError
except ImportError:
# except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.utils.exceptions import DisplayError

View File

@@ -16,10 +16,11 @@ import tempfile
import os
import shutil
try:
# try:
# Try relative imports first
from .utils.exceptions import UpdateError
except ImportError:
# except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.utils.exceptions import UpdateError