mirror of
https://github.com/pacnpal/Pac-cogs.git
synced 2025-12-21 03:11:07 -05:00
FFmpeg Binary Management:
Fixed tar.xz extraction by separating decompression and extraction steps Added proper error handling for archive operations Improved binary verification process Enhanced cleanup of temporary files Exception Handling: Added missing exceptions to utils/exceptions.py Fixed exception imports in exceptions.py Added proper error types for all operations Improved error messages and context URL Processing: Added pre-filtering for URLs before yt-dlp checks Added common video platform patterns Reduced error logging noise Improved URL validation efficiency Code Organization: Centralized exceptions in utils/exceptions.py Proper re-exports in exceptions.py Consistent error handling across components Better file operation handling
This commit is contained in:
@@ -14,6 +14,7 @@ from pathlib import Path
|
|||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
from typing import Optional, Dict, List
|
from typing import Optional, Dict, List
|
||||||
import time
|
import time
|
||||||
|
import lzma
|
||||||
|
|
||||||
from .exceptions import DownloadError
|
from .exceptions import DownloadError
|
||||||
|
|
||||||
@@ -261,26 +262,43 @@ class FFmpegDownloader:
|
|||||||
|
|
||||||
def _extract_tar(self, archive_path: Path, temp_dir: str):
|
def _extract_tar(self, archive_path: Path, temp_dir: str):
|
||||||
"""Extract from tar archive (Linux/macOS)"""
|
"""Extract from tar archive (Linux/macOS)"""
|
||||||
with tarfile.open(archive_path, "r:xz") as tar_ref:
|
try:
|
||||||
binary_names = self._get_binary_names()
|
# First decompress the .xz file
|
||||||
for binary_name in binary_names:
|
decompressed_path = archive_path.with_suffix('')
|
||||||
# BtbN's builds have binaries in bin directory
|
with lzma.open(archive_path, 'rb') as compressed:
|
||||||
binary_files = [
|
with open(decompressed_path, 'wb') as decompressed:
|
||||||
f for f in tar_ref.getnames() if f.endswith(f"/bin/{binary_name}")
|
shutil.copyfileobj(compressed, decompressed)
|
||||||
]
|
|
||||||
if not binary_files:
|
|
||||||
# Fallback to old structure
|
|
||||||
binary_files = [
|
|
||||||
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")
|
|
||||||
|
|
||||||
tar_ref.extract(binary_files[0], temp_dir)
|
# Then extract from the tar file
|
||||||
extracted_path = Path(temp_dir) / binary_files[0]
|
with tarfile.open(decompressed_path, "r:") as tar_ref:
|
||||||
target_path = self.base_dir / binary_name
|
binary_names = self._get_binary_names()
|
||||||
shutil.copy2(extracted_path, target_path)
|
for binary_name in binary_names:
|
||||||
logger.info(f"Extracted {binary_name} to {target_path}")
|
# BtbN's builds have binaries in bin directory
|
||||||
|
binary_files = [
|
||||||
|
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}")
|
||||||
|
]
|
||||||
|
if not binary_files:
|
||||||
|
raise DownloadError(f"{binary_name} not found in archive")
|
||||||
|
|
||||||
|
tar_ref.extract(binary_files[0], temp_dir)
|
||||||
|
extracted_path = Path(temp_dir) / binary_files[0]
|
||||||
|
target_path = self.base_dir / binary_name
|
||||||
|
shutil.copy2(extracted_path, target_path)
|
||||||
|
logger.info(f"Extracted {binary_name} to {target_path}")
|
||||||
|
|
||||||
|
# Clean up decompressed file
|
||||||
|
try:
|
||||||
|
os.unlink(decompressed_path)
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Failed to clean up decompressed file: {e}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
raise DownloadError(f"Failed to extract tar.xz archive: {e}")
|
||||||
|
|
||||||
def verify(self) -> bool:
|
def verify(self) -> bool:
|
||||||
"""Verify FFmpeg and FFprobe binaries work"""
|
"""Verify FFmpeg and FFprobe binaries work"""
|
||||||
@@ -299,7 +317,7 @@ class FFmpegDownloader:
|
|||||||
|
|
||||||
# Test FFmpeg functionality with enhanced error handling
|
# Test FFmpeg functionality with enhanced error handling
|
||||||
try:
|
try:
|
||||||
ffmpeg_result = subprocess.run(
|
result = subprocess.run(
|
||||||
[str(self.ffmpeg_path), "-version"],
|
[str(self.ffmpeg_path), "-version"],
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.PIPE,
|
stderr=subprocess.PIPE,
|
||||||
@@ -317,7 +335,7 @@ class FFmpegDownloader:
|
|||||||
|
|
||||||
# Test FFprobe functionality with enhanced error handling
|
# Test FFprobe functionality with enhanced error handling
|
||||||
try:
|
try:
|
||||||
ffprobe_result = subprocess.run(
|
result = subprocess.run(
|
||||||
[str(self.ffprobe_path), "-version"],
|
[str(self.ffprobe_path), "-version"],
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.PIPE,
|
stderr=subprocess.PIPE,
|
||||||
@@ -334,25 +352,18 @@ class FFmpegDownloader:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
# Check results
|
# Check results
|
||||||
if ffmpeg_result.returncode == 0 and ffprobe_result.returncode == 0:
|
if result.returncode == 0:
|
||||||
try:
|
try:
|
||||||
ffmpeg_version = ffmpeg_result.stdout.split("\n")[0]
|
ffmpeg_version = result.stdout.split("\n")[0]
|
||||||
ffprobe_version = ffprobe_result.stdout.split("\n")[0]
|
|
||||||
logger.info(f"FFmpeg verification successful: {ffmpeg_version}")
|
logger.info(f"FFmpeg verification successful: {ffmpeg_version}")
|
||||||
logger.info(f"FFprobe verification successful: {ffprobe_version}")
|
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to parse version output: {e}")
|
logger.error(f"Failed to parse version output: {e}")
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
if ffmpeg_result.returncode != 0:
|
logger.error(
|
||||||
logger.error(
|
f"FFmpeg verification failed with code {result.returncode}: {result.stderr}"
|
||||||
f"FFmpeg verification failed with code {ffmpeg_result.returncode}: {ffmpeg_result.stderr}"
|
)
|
||||||
)
|
|
||||||
if ffprobe_result.returncode != 0:
|
|
||||||
logger.error(
|
|
||||||
f"FFprobe verification failed with code {ffprobe_result.returncode}: {ffprobe_result.stderr}"
|
|
||||||
)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
Reference in New Issue
Block a user