mirror of
https://github.com/pacnpal/Pac-cogs.git
synced 2025-12-20 02:41:06 -05:00
fixed imports again
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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",
|
||||
]
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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}")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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(),
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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",
|
||||
]
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
@@ -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)}")
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user