mirror of
https://github.com/pacnpal/Pac-cogs.git
synced 2025-12-20 02:41:06 -05:00
Core Systems:
Component-based architecture with lifecycle management Enhanced error handling and recovery mechanisms Comprehensive state management and tracking Event-driven architecture with monitoring Queue Management: Multiple processing strategies for different scenarios Advanced state management with recovery Comprehensive metrics and health monitoring Sophisticated cleanup system with multiple strategies Processing Pipeline: Enhanced message handling with validation Improved URL extraction and processing Better queue management and monitoring Advanced cleanup mechanisms Overall Benefits: Better code organization and maintainability Improved error handling and recovery Enhanced monitoring and reporting More robust and reliable system
This commit is contained in:
316
videoarchiver/processor/status_display.py
Normal file
316
videoarchiver/processor/status_display.py
Normal file
@@ -0,0 +1,316 @@
|
||||
"""Module for handling queue status display and formatting"""
|
||||
|
||||
import discord
|
||||
from enum import Enum
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from typing import Dict, Any, List, Optional
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger("VideoArchiver")
|
||||
|
||||
class DisplayTheme:
|
||||
"""Defines display themes"""
|
||||
DEFAULT = {
|
||||
"title_color": discord.Color.blue(),
|
||||
"success_color": discord.Color.green(),
|
||||
"warning_color": discord.Color.gold(),
|
||||
"error_color": discord.Color.red(),
|
||||
"info_color": discord.Color.blurple()
|
||||
}
|
||||
|
||||
@dataclass
|
||||
class DisplayTemplate:
|
||||
"""Template for status display sections"""
|
||||
name: str
|
||||
format_string: str
|
||||
inline: bool = False
|
||||
order: int = 0
|
||||
condition: Optional[str] = None
|
||||
|
||||
class DisplaySection(Enum):
|
||||
"""Available display sections"""
|
||||
QUEUE_STATS = "queue_stats"
|
||||
DOWNLOADS = "downloads"
|
||||
COMPRESSIONS = "compressions"
|
||||
ERRORS = "errors"
|
||||
HARDWARE = "hardware"
|
||||
|
||||
class StatusFormatter:
|
||||
"""Formats status information for display"""
|
||||
|
||||
@staticmethod
|
||||
def format_bytes(bytes: int) -> str:
|
||||
"""Format bytes into human readable format"""
|
||||
for unit in ['B', 'KB', 'MB', 'GB']:
|
||||
if bytes < 1024:
|
||||
return f"{bytes:.1f}{unit}"
|
||||
bytes /= 1024
|
||||
return f"{bytes:.1f}TB"
|
||||
|
||||
@staticmethod
|
||||
def format_time(seconds: float) -> str:
|
||||
"""Format time duration"""
|
||||
if seconds < 60:
|
||||
return f"{seconds:.1f}s"
|
||||
minutes = seconds / 60
|
||||
if minutes < 60:
|
||||
return f"{minutes:.1f}m"
|
||||
hours = minutes / 60
|
||||
return f"{hours:.1f}h"
|
||||
|
||||
@staticmethod
|
||||
def format_percentage(value: float) -> str:
|
||||
"""Format percentage value"""
|
||||
return f"{value:.1f}%"
|
||||
|
||||
class DisplayManager:
|
||||
"""Manages status display configuration"""
|
||||
|
||||
def __init__(self):
|
||||
self.templates: Dict[DisplaySection, DisplayTemplate] = {
|
||||
DisplaySection.QUEUE_STATS: DisplayTemplate(
|
||||
name="Queue Statistics",
|
||||
format_string=(
|
||||
"```\n"
|
||||
"Pending: {pending}\n"
|
||||
"Processing: {processing}\n"
|
||||
"Completed: {completed}\n"
|
||||
"Failed: {failed}\n"
|
||||
"Success Rate: {success_rate}\n"
|
||||
"Avg Processing Time: {avg_processing_time}\n"
|
||||
"```"
|
||||
),
|
||||
order=1
|
||||
),
|
||||
DisplaySection.DOWNLOADS: DisplayTemplate(
|
||||
name="Active Downloads",
|
||||
format_string=(
|
||||
"```\n"
|
||||
"URL: {url}\n"
|
||||
"Progress: {percent}\n"
|
||||
"Speed: {speed}\n"
|
||||
"ETA: {eta}\n"
|
||||
"Size: {size}\n"
|
||||
"Started: {start_time}\n"
|
||||
"Retries: {retries}\n"
|
||||
"```"
|
||||
),
|
||||
order=2
|
||||
),
|
||||
DisplaySection.COMPRESSIONS: DisplayTemplate(
|
||||
name="Active Compressions",
|
||||
format_string=(
|
||||
"```\n"
|
||||
"File: {filename}\n"
|
||||
"Progress: {percent}\n"
|
||||
"Time Elapsed: {elapsed_time}\n"
|
||||
"Input Size: {input_size}\n"
|
||||
"Current Size: {current_size}\n"
|
||||
"Target Size: {target_size}\n"
|
||||
"Codec: {codec}\n"
|
||||
"Hardware Accel: {hardware_accel}\n"
|
||||
"```"
|
||||
),
|
||||
order=3
|
||||
),
|
||||
DisplaySection.ERRORS: DisplayTemplate(
|
||||
name="Error Statistics",
|
||||
format_string="```\n{error_stats}```",
|
||||
condition="has_errors",
|
||||
order=4
|
||||
),
|
||||
DisplaySection.HARDWARE: DisplayTemplate(
|
||||
name="Hardware Statistics",
|
||||
format_string=(
|
||||
"```\n"
|
||||
"Hardware Accel Failures: {hw_failures}\n"
|
||||
"Compression Failures: {comp_failures}\n"
|
||||
"Peak Memory Usage: {memory_usage}\n"
|
||||
"```"
|
||||
),
|
||||
order=5
|
||||
)
|
||||
}
|
||||
self.theme = DisplayTheme.DEFAULT
|
||||
|
||||
class StatusDisplay:
|
||||
"""Handles formatting and display of queue status information"""
|
||||
|
||||
def __init__(self):
|
||||
self.display_manager = DisplayManager()
|
||||
self.formatter = StatusFormatter()
|
||||
|
||||
async def create_queue_status_embed(
|
||||
self,
|
||||
queue_status: Dict[str, Any],
|
||||
active_ops: Dict[str, Any]
|
||||
) -> discord.Embed:
|
||||
"""Create an embed displaying queue status and active operations"""
|
||||
embed = discord.Embed(
|
||||
title="Queue Status Details",
|
||||
color=self.display_manager.theme["title_color"],
|
||||
timestamp=datetime.utcnow()
|
||||
)
|
||||
|
||||
# Add sections in order
|
||||
sections = sorted(
|
||||
self.display_manager.templates.items(),
|
||||
key=lambda x: x[1].order
|
||||
)
|
||||
|
||||
for section, template in sections:
|
||||
# Check condition if exists
|
||||
if template.condition:
|
||||
if not self._check_condition(template.condition, queue_status, active_ops):
|
||||
continue
|
||||
|
||||
# Add section based on type
|
||||
if section == DisplaySection.QUEUE_STATS:
|
||||
self._add_queue_statistics(embed, queue_status, template)
|
||||
elif section == DisplaySection.DOWNLOADS:
|
||||
self._add_active_downloads(embed, active_ops.get('downloads', {}), template)
|
||||
elif section == DisplaySection.COMPRESSIONS:
|
||||
self._add_active_compressions(embed, active_ops.get('compressions', {}), template)
|
||||
elif section == DisplaySection.ERRORS:
|
||||
self._add_error_statistics(embed, queue_status, template)
|
||||
elif section == DisplaySection.HARDWARE:
|
||||
self._add_hardware_statistics(embed, queue_status, template)
|
||||
|
||||
return embed
|
||||
|
||||
def _check_condition(
|
||||
self,
|
||||
condition: str,
|
||||
queue_status: Dict[str, Any],
|
||||
active_ops: Dict[str, Any]
|
||||
) -> bool:
|
||||
"""Check if condition for displaying section is met"""
|
||||
if condition == "has_errors":
|
||||
return bool(queue_status["metrics"]["errors_by_type"])
|
||||
return True
|
||||
|
||||
def _add_queue_statistics(
|
||||
self,
|
||||
embed: discord.Embed,
|
||||
queue_status: Dict[str, Any],
|
||||
template: DisplayTemplate
|
||||
) -> None:
|
||||
"""Add queue statistics to the embed"""
|
||||
embed.add_field(
|
||||
name=template.name,
|
||||
value=template.format_string.format(
|
||||
pending=queue_status['pending'],
|
||||
processing=queue_status['processing'],
|
||||
completed=queue_status['completed'],
|
||||
failed=queue_status['failed'],
|
||||
success_rate=self.formatter.format_percentage(
|
||||
queue_status['metrics']['success_rate'] * 100
|
||||
),
|
||||
avg_processing_time=self.formatter.format_time(
|
||||
queue_status['metrics']['avg_processing_time']
|
||||
)
|
||||
),
|
||||
inline=template.inline
|
||||
)
|
||||
|
||||
def _add_active_downloads(
|
||||
self,
|
||||
embed: discord.Embed,
|
||||
downloads: Dict[str, Any],
|
||||
template: DisplayTemplate
|
||||
) -> None:
|
||||
"""Add active downloads information to the embed"""
|
||||
if downloads:
|
||||
content = []
|
||||
for url, progress in downloads.items():
|
||||
content.append(template.format_string.format(
|
||||
url=url[:50] + "..." if len(url) > 50 else url,
|
||||
percent=self.formatter.format_percentage(progress.get('percent', 0)),
|
||||
speed=progress.get('speed', 'N/A'),
|
||||
eta=progress.get('eta', 'N/A'),
|
||||
size=f"{self.formatter.format_bytes(progress.get('downloaded_bytes', 0))}/"
|
||||
f"{self.formatter.format_bytes(progress.get('total_bytes', 0))}",
|
||||
start_time=progress.get('start_time', 'N/A'),
|
||||
retries=progress.get('retries', 0)
|
||||
))
|
||||
embed.add_field(
|
||||
name=template.name,
|
||||
value="".join(content),
|
||||
inline=template.inline
|
||||
)
|
||||
else:
|
||||
embed.add_field(
|
||||
name=template.name,
|
||||
value="```\nNo active downloads```",
|
||||
inline=template.inline
|
||||
)
|
||||
|
||||
def _add_active_compressions(
|
||||
self,
|
||||
embed: discord.Embed,
|
||||
compressions: Dict[str, Any],
|
||||
template: DisplayTemplate
|
||||
) -> None:
|
||||
"""Add active compressions information to the embed"""
|
||||
if compressions:
|
||||
content = []
|
||||
for file_id, progress in compressions.items():
|
||||
content.append(template.format_string.format(
|
||||
filename=progress.get('filename', 'Unknown'),
|
||||
percent=self.formatter.format_percentage(progress.get('percent', 0)),
|
||||
elapsed_time=progress.get('elapsed_time', 'N/A'),
|
||||
input_size=self.formatter.format_bytes(progress.get('input_size', 0)),
|
||||
current_size=self.formatter.format_bytes(progress.get('current_size', 0)),
|
||||
target_size=self.formatter.format_bytes(progress.get('target_size', 0)),
|
||||
codec=progress.get('codec', 'Unknown'),
|
||||
hardware_accel=progress.get('hardware_accel', False)
|
||||
))
|
||||
embed.add_field(
|
||||
name=template.name,
|
||||
value="".join(content),
|
||||
inline=template.inline
|
||||
)
|
||||
else:
|
||||
embed.add_field(
|
||||
name=template.name,
|
||||
value="```\nNo active compressions```",
|
||||
inline=template.inline
|
||||
)
|
||||
|
||||
def _add_error_statistics(
|
||||
self,
|
||||
embed: discord.Embed,
|
||||
queue_status: Dict[str, Any],
|
||||
template: DisplayTemplate
|
||||
) -> None:
|
||||
"""Add error statistics to the embed"""
|
||||
if queue_status["metrics"]["errors_by_type"]:
|
||||
error_stats = "\n".join(
|
||||
f"{error_type}: {count}"
|
||||
for error_type, count in queue_status["metrics"]["errors_by_type"].items()
|
||||
)
|
||||
embed.add_field(
|
||||
name=template.name,
|
||||
value=template.format_string.format(error_stats=error_stats),
|
||||
inline=template.inline
|
||||
)
|
||||
|
||||
def _add_hardware_statistics(
|
||||
self,
|
||||
embed: discord.Embed,
|
||||
queue_status: Dict[str, Any],
|
||||
template: DisplayTemplate
|
||||
) -> None:
|
||||
"""Add hardware statistics to the embed"""
|
||||
embed.add_field(
|
||||
name=template.name,
|
||||
value=template.format_string.format(
|
||||
hw_failures=queue_status['metrics']['hardware_accel_failures'],
|
||||
comp_failures=queue_status['metrics']['compression_failures'],
|
||||
memory_usage=self.formatter.format_bytes(
|
||||
queue_status['metrics']['peak_memory_usage'] * 1024 * 1024 # Convert MB to bytes
|
||||
)
|
||||
),
|
||||
inline=template.inline
|
||||
)
|
||||
Reference in New Issue
Block a user