mirror of
https://github.com/pacnpal/Pac-cogs.git
synced 2025-12-20 10:51:05 -05:00
313 lines
11 KiB
Python
313 lines
11 KiB
Python
"""Progress tracking module."""
|
|
|
|
import logging
|
|
from typing import Dict, Any, Optional
|
|
from datetime import datetime
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
class ProgressTracker:
|
|
"""Progress tracker singleton."""
|
|
_instance = None
|
|
|
|
def __new__(cls):
|
|
if cls._instance is None:
|
|
cls._instance = super().__new__(cls)
|
|
cls._instance._initialized = False
|
|
return cls._instance
|
|
|
|
def __init__(self):
|
|
if not hasattr(self, '_initialized'):
|
|
self._data: Dict[str, Dict[str, Any]] = {}
|
|
self._initialized = True
|
|
|
|
def update(self, key: str, data: Dict[str, Any]) -> None:
|
|
"""Update progress for a key."""
|
|
if key not in self._data:
|
|
self._data[key] = {
|
|
'active': True,
|
|
'start_time': datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S"),
|
|
'percent': 0
|
|
}
|
|
self._data[key].update(data)
|
|
self._data[key]['last_update'] = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")
|
|
logger.debug(f"Progress for {key}: {self._data[key].get('percent', 0)}%")
|
|
|
|
def get(self, key: Optional[str] = None) -> Dict[str, Any]:
|
|
"""Get progress for a key."""
|
|
if key is None:
|
|
return self._data
|
|
return self._data.get(key, {})
|
|
|
|
def complete(self, key: str) -> None:
|
|
"""Mark progress as complete."""
|
|
if key in self._data:
|
|
self._data[key]['active'] = False
|
|
logger.info(f"Operation completed for {key}")
|
|
|
|
def clear(self) -> None:
|
|
"""Clear all progress data."""
|
|
self._data.clear()
|
|
logger.info("Progress data cleared")
|
|
|
|
_tracker = ProgressTracker()
|
|
|
|
def get_compression(self, file_path: Optional[str] = None) -> Dict[str, Any]:
|
|
"""Get compression progress."""
|
|
if file_path is None:
|
|
return self._compressions
|
|
return self._compressions.get(file_path, {})
|
|
|
|
def complete_download(self, url: str) -> None:
|
|
"""Mark download as complete."""
|
|
if url in self._downloads:
|
|
self._downloads[url]['active'] = False
|
|
logger.info(f"Download completed for {url}")
|
|
|
|
def complete_compression(self, file_path: str) -> None:
|
|
"""Mark compression as complete."""
|
|
if file_path in self._compressions:
|
|
self._compressions[file_path]['active'] = False
|
|
logger.info(f"Compression completed for {file_path}")
|
|
|
|
def clear(self) -> None:
|
|
"""Clear all progress data."""
|
|
self._downloads.clear()
|
|
self._compressions.clear()
|
|
logger.info("Progress data cleared")
|
|
|
|
# Global instance
|
|
_tracker = ProgressTrack
|
|
|
|
# Global instance
|
|
_tracker = ProgressTracker()
|
|
|
|
def get_tracker() -> Progre
|
|
"""Clear all progress tracking"""
|
|
self._download_progress.clear()
|
|
self._compression_progress.clear()
|
|
logger.info("Cleared all progress tracking data")
|
|
|
|
# Create singleton instance
|
|
progress_tracker = ProgressTracker()
|
|
|
|
def get_progress_tracker() -> ProgressTracker:
|
|
|
|
def mark_compression_complete(self, file_path: str) -> None:
|
|
"""Mark a compression operation as complete"""
|
|
if file_path in self._compression_progress:
|
|
self._compression_progress[file_path]['active'] = False
|
|
logger.info(f"Compression completed for {file_path}")
|
|
|
|
def clear_progress(self) -> None:
|
|
"""Clear all progress tracking"""
|
|
self._download_progress.clear()
|
|
self._compression_progress.clear()
|
|
logger.info("Cleared all progress tracking data")
|
|
|
|
# Create singleton instance
|
|
progress_tracker = ProgressTracker()
|
|
|
|
# Export the singleton instance
|
|
def get_progress_tracker() -> ProgressTracker:
|
|
|
|
|
|
Args:
|
|
data: Dictionary containing download progress data
|
|
"""
|
|
try:
|
|
info_dict = data.get("info_dict", {})
|
|
url = info_dict.get("webpage_url")
|
|
if not url or url not in self._download_progress:
|
|
return
|
|
|
|
if data.get("status") == "downloading":
|
|
percent_str = data.get("_percent_str", "0").replace("%", "")
|
|
try:
|
|
percent = float(percent_str)
|
|
except ValueError:
|
|
percent = 0.0
|
|
|
|
total_bytes = (
|
|
data.get("total_bytes", 0) or
|
|
data.get("total_bytes_estimate", 0)
|
|
)
|
|
|
|
self._download_progress[url].update({
|
|
"active": True,
|
|
"percent": percent,
|
|
"speed": data.get("_speed_str", "N/A"),
|
|
"eta": data.get("_eta_str", "N/A"),
|
|
"downloaded_bytes": data.get("downloaded_bytes", 0),
|
|
"total_bytes": total_bytes,
|
|
"retries": data.get("retry_count", 0),
|
|
"fragment_count": data.get("fragment_count", 0),
|
|
"fragment_index": data.get("fragment_index", 0),
|
|
"video_title": info_dict.get("title", "Unknown"),
|
|
"extractor": info_dict.get("extractor", "Unknown"),
|
|
"format": info_dict.get("format", "Unknown"),
|
|
"resolution": info_dict.get("resolution", "Unknown"),
|
|
"fps": info_dict.get("fps", "Unknown"),
|
|
"last_update": datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")
|
|
})
|
|
|
|
logger.debug(
|
|
f"Download progress for {url}: "
|
|
f"{percent:.1f}% at {self._download_progress[url]['speed']}, "
|
|
f"ETA: {self._download_progress[url]['eta']}"
|
|
)
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error updating download progress: {e}", exc_info=True)
|
|
|
|
def end_download(self, url: str, status: ProgressStatus = ProgressStatus.COMPLETED) -> None:
|
|
"""
|
|
Mark a download as completed.
|
|
|
|
Args:
|
|
url: The URL being downloaded
|
|
status: The final status of the download
|
|
"""
|
|
if url in self._download_progress:
|
|
self._download_progress[url]["active"] = False
|
|
logger.info(f"Download {status.value} for {url}")
|
|
|
|
def start_compression(self, params: CompressionParams) -> None:
|
|
"""
|
|
Initialize progress tracking for compression.
|
|
|
|
Args:
|
|
params: Compression parameters
|
|
"""
|
|
current_time = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")
|
|
self._compression_progress[params.input_file] = CompressionProgress(
|
|
active=True,
|
|
filename=params.input_file,
|
|
start_time=current_time,
|
|
percent=0.0,
|
|
elapsed_time="0:00",
|
|
input_size=params.input_size,
|
|
current_size=0,
|
|
target_size=params.target_size,
|
|
codec=params.codec_params.get("c:v", "unknown"),
|
|
hardware_accel=params.use_hardware,
|
|
preset=params.codec_params.get("preset", "unknown"),
|
|
crf=params.codec_params.get("crf", "unknown"),
|
|
duration=params.duration,
|
|
bitrate=params.codec_params.get("b:v", "unknown"),
|
|
audio_codec=params.codec_params.get("c:a", "unknown"),
|
|
audio_bitrate=params.codec_params.get("b:a", "unknown"),
|
|
last_update=current_time,
|
|
current_time=None
|
|
)
|
|
|
|
def update_compression_progress(
|
|
self,
|
|
input_file: str,
|
|
progress: float,
|
|
elapsed_time: str,
|
|
current_size: int,
|
|
current_time: float
|
|
) -> None:
|
|
"""
|
|
Update compression progress information.
|
|
|
|
Args:
|
|
input_file: The input file being compressed
|
|
progress: Current progress percentage (0-100)
|
|
elapsed_time: Time elapsed as string
|
|
current_size: Current file size in bytes
|
|
current_time: Current timestamp in seconds
|
|
"""
|
|
if input_file in self._compression_progress:
|
|
self._compression_progress[input_file].update({
|
|
"percent": max(0.0, min(100.0, progress)),
|
|
"elapsed_time": elapsed_time,
|
|
"current_size": current_size,
|
|
"current_time": current_time,
|
|
"last_update": datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")
|
|
})
|
|
|
|
logger.debug(
|
|
f"Compression progress for {input_file}: "
|
|
f"{progress:.1f}%, Size: {current_size}/{self._compression_progress[input_file]['target_size']} bytes"
|
|
)
|
|
|
|
def end_compression(
|
|
self,
|
|
input_file: str,
|
|
status: ProgressStatus = ProgressStatus.COMPLETED
|
|
) -> None:
|
|
"""
|
|
Mark a compression operation as completed.
|
|
|
|
Args:
|
|
input_file: The input file being compressed
|
|
status: The final status of the compression
|
|
"""
|
|
if input_file in self._compression_progress:
|
|
self._compression_progress[input_file]["active"] = False
|
|
logger.info(f"Compression {status.value} for {input_file}")
|
|
|
|
def get_download_progress(self, url: Optional[str] = None) -> Optional[DownloadProgress]:
|
|
"""
|
|
Get progress information for a download.
|
|
|
|
Args:
|
|
url: Optional URL to get progress for. If None, returns all progress.
|
|
|
|
Returns:
|
|
Progress information for the specified download or None if not found
|
|
"""
|
|
if url is None:
|
|
return self._download_progress
|
|
return self._download_progress.get(url)
|
|
|
|
def get_compression_progress(
|
|
self,
|
|
input_file: Optional[str] = None
|
|
) -> Optional[CompressionProgress]:
|
|
"""
|
|
Get progress information for a compression operation.
|
|
|
|
Args:
|
|
input_file: Optional file to get progress for. If None, returns all progress.
|
|
|
|
Returns:
|
|
Progress information for the specified compression or None if not found
|
|
"""
|
|
if input_file is None:
|
|
return self._compression_progress
|
|
return self._compression_progress.get(input_file)
|
|
|
|
def get_active_downloads(self) -> Dict[str, DownloadProgress]:
|
|
"""
|
|
Get all active downloads.
|
|
|
|
Returns:
|
|
Dictionary of active downloads and their progress
|
|
"""
|
|
return {
|
|
url: progress
|
|
for url, progress in self._download_progress.items()
|
|
if progress.get("active", False)
|
|
}
|
|
|
|
def get_active_compressions(self) -> Dict[str, CompressionProgress]:
|
|
"""
|
|
Get all active compression operations.
|
|
|
|
Returns:
|
|
Dictionary of active compressions and their progress
|
|
"""
|
|
return {
|
|
input_file: progress
|
|
for input_file, progress in self._compression_progress.items()
|
|
if progress.get("active", False)
|
|
}
|
|
|
|
def clear_progress(self) -> None:
|
|
"""Clear all progress tracking"""
|
|
self._download_progress.clear()
|
|
self._compression_progress.clear()
|
|
logger.info("Cleared |