mirror of
https://github.com/Arrowar/StreamingCommunity.git
synced 2025-06-05 02:55:25 +00:00
Fix ffmpeg installer
This commit is contained in:
parent
31016f45dd
commit
b6319b42bd
@ -141,8 +141,7 @@ class TOR_downloader:
|
||||
console.print("\n[bold green]🔗 Dettagli Torrent Aggiunto:[/bold green]")
|
||||
console.print(f"[yellow]Nome:[/yellow] {torrent_info.get('name', torrent_name)}")
|
||||
console.print(f"[yellow]Hash:[/yellow] {torrent_info['hash']}")
|
||||
console.print(f"[yellow]Dimensione:[/yellow] {torrent_info.get('size', 'Non disponibile'):,} bytes")
|
||||
console.print(f"[yellow]Stato:[/yellow] {torrent_info.get('state', 'Sconosciuto')}")
|
||||
console.print(f"[yellow]Dimensione:[/yellow] {internet_manager.format_file_size(torrent_info.get('size'))}")
|
||||
print()
|
||||
|
||||
# Salva l'hash per usi successivi e il path
|
||||
|
@ -41,8 +41,20 @@ FFMPEG_CONFIGURATION = {
|
||||
}
|
||||
|
||||
|
||||
|
||||
class FFMPEGDownloader:
|
||||
"""
|
||||
A class for downloading and managing FFmpeg executables.
|
||||
|
||||
This class handles the detection of the operating system, downloading of FFmpeg binaries,
|
||||
and management of the FFmpeg executables (ffmpeg, ffprobe, and ffplay).
|
||||
|
||||
Attributes:
|
||||
os_name (str): The detected operating system name
|
||||
arch (str): The system architecture (e.g., x86_64, arm64)
|
||||
home_dir (str): User's home directory path
|
||||
base_dir (str): Base directory for storing FFmpeg binaries
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.os_name = self._detect_system()
|
||||
self.arch = self._detect_arch()
|
||||
@ -50,20 +62,32 @@ class FFMPEGDownloader:
|
||||
self.base_dir = self._get_base_directory()
|
||||
|
||||
def _detect_system(self) -> str:
|
||||
"""Detect and normalize operating system name."""
|
||||
system = platform.system().lower()
|
||||
"""
|
||||
Detect and normalize the operating system name.
|
||||
|
||||
Returns:
|
||||
str: Normalized operating system name ('windows', 'darwin', or 'linux')
|
||||
|
||||
Raises:
|
||||
ValueError: If the operating system is not supported
|
||||
"""
|
||||
system = platform.system().lower()
|
||||
if system in FFMPEG_CONFIGURATION:
|
||||
return system
|
||||
|
||||
raise ValueError(f"Unsupported operating system: {system}")
|
||||
|
||||
def _detect_arch(self) -> str:
|
||||
"""
|
||||
Detect system architecture
|
||||
Detect and normalize the system architecture.
|
||||
|
||||
Returns:
|
||||
str: Normalized architecture name (e.g., 'x86_64', 'arm64')
|
||||
|
||||
The method normalizes various architecture names to consistent values:
|
||||
- amd64/x86_64/x64 -> x86_64
|
||||
- arm64/aarch64 -> arm64
|
||||
"""
|
||||
machine = platform.machine().lower()
|
||||
|
||||
arch_map = {
|
||||
'amd64': 'x86_64',
|
||||
'x86_64': 'x86_64',
|
||||
@ -71,59 +95,80 @@ class FFMPEGDownloader:
|
||||
'arm64': 'arm64',
|
||||
'aarch64': 'arm64'
|
||||
}
|
||||
|
||||
return arch_map.get(machine, machine)
|
||||
|
||||
def _get_base_directory(self) -> str:
|
||||
"""
|
||||
Get base directory for binaries
|
||||
Get and create the base directory for storing FFmpeg binaries.
|
||||
|
||||
Returns:
|
||||
str: Path to the base directory
|
||||
|
||||
The directory location varies by operating system:
|
||||
- Windows: C:\\binary
|
||||
- macOS: ~/Applications/binary
|
||||
- Linux: ~/.local/bin/binary
|
||||
"""
|
||||
base_dir = FFMPEG_CONFIGURATION[self.os_name]['base_dir'](self.home_dir)
|
||||
os.makedirs(base_dir, exist_ok=True)
|
||||
|
||||
return base_dir
|
||||
|
||||
def _check_existing_binaries(self) -> Tuple[Optional[str], Optional[str]]:
|
||||
def _check_existing_binaries(self) -> Tuple[Optional[str], Optional[str], Optional[str]]:
|
||||
"""
|
||||
Check if FFmpeg binaries already exist in the base directory
|
||||
Check if FFmpeg binaries already exist in the base directory.
|
||||
|
||||
Returns:
|
||||
Tuple[Optional[str], Optional[str], Optional[str]]: Paths to ffmpeg, ffprobe, and ffplay executables.
|
||||
Returns None for each executable that is not found.
|
||||
"""
|
||||
config = FFMPEG_CONFIGURATION[self.os_name]
|
||||
executables = config['executables']
|
||||
|
||||
found_executables = []
|
||||
|
||||
for executable in executables:
|
||||
|
||||
# Search for exact executable in base directory
|
||||
exe_paths = glob.glob(os.path.join(self.base_dir, executable))
|
||||
if exe_paths:
|
||||
found_executables.append(exe_paths[0])
|
||||
else:
|
||||
found_executables.append(None)
|
||||
|
||||
# Return paths if both executables are found
|
||||
if len(found_executables) == len(executables):
|
||||
return tuple(found_executables)
|
||||
return tuple(found_executables) if len(found_executables) == 3 else (None, None, None)
|
||||
|
||||
return None, None
|
||||
|
||||
def _get_latest_version(self) -> str:
|
||||
def _get_latest_version(self) -> Optional[str]:
|
||||
"""
|
||||
Get the latest FFmpeg version
|
||||
Get the latest FFmpeg version from the official website.
|
||||
|
||||
Returns:
|
||||
Optional[str]: The latest version string, or None if retrieval fails
|
||||
|
||||
Raises:
|
||||
requests.exceptions.RequestException: If there are network-related errors
|
||||
"""
|
||||
try:
|
||||
version_url = 'https://www.gyan.dev/ffmpeg/builds/release-version'
|
||||
return requests.get(version_url).text.strip()
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Unable to get version: {e}")
|
||||
return None
|
||||
|
||||
def _download_file(self, url: str, destination: str) -> bool:
|
||||
"""
|
||||
Download with Rich progress bar
|
||||
Download a file from URL with a Rich progress bar display.
|
||||
|
||||
Parameters:
|
||||
url (str): The URL to download the file from. Should be a direct download link.
|
||||
destination (str): Local file path where the downloaded file will be saved.
|
||||
|
||||
Returns:
|
||||
bool: True if download was successful, False otherwise.
|
||||
|
||||
Raises:
|
||||
requests.exceptions.RequestException: If there are network-related errors
|
||||
IOError: If there are issues writing to the destination file
|
||||
"""
|
||||
try:
|
||||
response = requests.get(url, stream=True)
|
||||
response.raise_for_status()
|
||||
|
||||
total_size = int(response.headers.get('content-length', 0))
|
||||
|
||||
with open(destination, 'wb') as file, \
|
||||
@ -136,140 +181,131 @@ class FFMPEGDownloader:
|
||||
) as progress:
|
||||
|
||||
download_task = progress.add_task("[green]Downloading FFmpeg", total=total_size)
|
||||
|
||||
for chunk in response.iter_content(chunk_size=8192):
|
||||
size = file.write(chunk)
|
||||
progress.update(download_task, advance=size)
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Download error: {e}")
|
||||
return False
|
||||
|
||||
def _extract_and_copy_binaries(self, archive_path: str) -> Tuple[Optional[str], Optional[str]]:
|
||||
def _extract_and_copy_binaries(self, archive_path: str) -> Tuple[Optional[str], Optional[str], Optional[str]]:
|
||||
"""
|
||||
Extract archive and copy executables to base directory
|
||||
Extract FFmpeg binaries from the downloaded archive and copy them to the base directory.
|
||||
|
||||
Parameters:
|
||||
archive_path (str): Path to the downloaded archive file
|
||||
|
||||
Returns:
|
||||
Tuple[Optional[str], Optional[str], Optional[str]]: Paths to the extracted ffmpeg,
|
||||
ffprobe, and ffplay executables. Returns None for each executable that couldn't be extracted.
|
||||
"""
|
||||
try:
|
||||
# Temporary extraction path
|
||||
extraction_path = os.path.join(self.base_dir, 'temp_extract')
|
||||
os.makedirs(extraction_path, exist_ok=True)
|
||||
|
||||
# Extract based on file type
|
||||
if archive_path.endswith('.zip'):
|
||||
with zipfile.ZipFile(archive_path, 'r') as zip_ref:
|
||||
zip_ref.extractall(extraction_path)
|
||||
elif archive_path.endswith('.tar.xz'):
|
||||
import lzma
|
||||
with lzma.open(archive_path, 'rb') as xz_file:
|
||||
with tarfile.open(fileobj=xz_file) as tar_ref:
|
||||
tar_ref.extractall(extraction_path)
|
||||
with tarfile.open(archive_path) as tar_ref:
|
||||
tar_ref.extractall(extraction_path)
|
||||
|
||||
# Find and copy executables
|
||||
config = FFMPEG_CONFIGURATION[self.os_name]
|
||||
executables = config['executables']
|
||||
|
||||
found_paths = []
|
||||
|
||||
for executable in executables:
|
||||
# Find executable in extracted files
|
||||
exe_paths = glob.glob(os.path.join(extraction_path, '**', executable), recursive=True)
|
||||
|
||||
if exe_paths:
|
||||
# Copy to base directory
|
||||
dest_path = os.path.join(self.base_dir, executable)
|
||||
shutil.copy2(exe_paths[0], dest_path)
|
||||
|
||||
# Set execution permissions for Unix-like systems
|
||||
if self.os_name != 'windows':
|
||||
os.chmod(dest_path, 0o755)
|
||||
|
||||
found_paths.append(dest_path)
|
||||
else:
|
||||
found_paths.append(None)
|
||||
|
||||
# Clean up temporary extraction directory
|
||||
shutil.rmtree(extraction_path, ignore_errors=True)
|
||||
|
||||
# Remove downloaded archive
|
||||
os.remove(archive_path)
|
||||
|
||||
# Return paths if both executables found
|
||||
if len(found_paths) == len(executables):
|
||||
return tuple(found_paths)
|
||||
|
||||
return None, None
|
||||
return tuple(found_paths) if len(found_paths) == 3 else (None, None, None)
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Extraction/copy error: {e}")
|
||||
return None, None
|
||||
return None, None, None
|
||||
|
||||
def download(self) -> Tuple[Optional[str], Optional[str]]:
|
||||
def download(self) -> Tuple[Optional[str], Optional[str], Optional[str]]:
|
||||
"""
|
||||
Main download procedure
|
||||
Returns paths of ffmpeg and ffprobe
|
||||
Main method to download and set up FFmpeg executables.
|
||||
|
||||
Returns:
|
||||
Tuple[Optional[str], Optional[str], Optional[str]]: Paths to ffmpeg, ffprobe, and ffplay executables.
|
||||
Returns None for each executable that couldn't be downloaded or set up.
|
||||
"""
|
||||
# First, check if binaries already exist in base directory
|
||||
existing_ffmpeg, existing_ffprobe, existing_ffplay = self._check_existing_binaries()
|
||||
if existing_ffmpeg and existing_ffprobe:
|
||||
return existing_ffmpeg, existing_ffprobe
|
||||
if all([existing_ffmpeg, existing_ffprobe, existing_ffplay]):
|
||||
return existing_ffmpeg, existing_ffprobe, existing_ffplay
|
||||
|
||||
# Get latest version
|
||||
version = self._get_latest_version()
|
||||
if not version:
|
||||
logging.error("Cannot proceed: version not found")
|
||||
return None, None
|
||||
return None, None, None
|
||||
|
||||
# Prepare configurations
|
||||
config = FFMPEG_CONFIGURATION[self.os_name]
|
||||
|
||||
# Build download URL
|
||||
download_url = config['download_url'].format(
|
||||
version=version,
|
||||
arch=self.arch
|
||||
)
|
||||
|
||||
# Download path
|
||||
download_path = os.path.join(
|
||||
self.base_dir,
|
||||
f'ffmpeg-{version}{config["file_extension"]}'
|
||||
)
|
||||
|
||||
# Download
|
||||
console.print(
|
||||
f"[bold blue]Downloading FFmpeg from:[/] {download_url}",
|
||||
)
|
||||
console.print(f"[bold blue]Downloading FFmpeg from:[/] {download_url}")
|
||||
if not self._download_file(download_url, download_path):
|
||||
return None, None
|
||||
return None, None, None
|
||||
|
||||
# Extract and copy binaries
|
||||
ffmpeg_path, ffprobe_path = self._extract_and_copy_binaries(download_path)
|
||||
|
||||
if ffmpeg_path and ffprobe_path:
|
||||
return ffmpeg_path, ffprobe_path
|
||||
|
||||
logging.error("FFmpeg executables not found")
|
||||
return None, None
|
||||
return self._extract_and_copy_binaries(download_path)
|
||||
|
||||
def check_ffmpeg() -> Tuple[Optional[str], Optional[str], Optional[str]]:
|
||||
"""
|
||||
Check for FFmpeg executables in the system and download them if not found.
|
||||
|
||||
def check_ffmpeg():
|
||||
Returns:
|
||||
Tuple[Optional[str], Optional[str], Optional[str]]: Paths to ffmpeg, ffprobe, and ffplay executables.
|
||||
Returns None for each executable that couldn't be found or downloaded.
|
||||
|
||||
The function first checks if FFmpeg executables are available in the system PATH:
|
||||
- On Windows, uses the 'where' command
|
||||
- On Unix-like systems, uses 'which'
|
||||
|
||||
If the executables are not found in PATH, it attempts to download and install them
|
||||
using the FFMPEGDownloader class.
|
||||
"""
|
||||
try:
|
||||
# First, use 'where' command to check existing binaries on Windows
|
||||
if platform.system().lower() == 'windows':
|
||||
ffmpeg_path = subprocess.check_output(['where', 'ffmpeg'], text=True).strip().split('\n')[0] if subprocess.call(['where', 'ffmpeg'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) == 0 else None
|
||||
ffprobe_path = subprocess.check_output(['where', 'ffprobe'], text=True).strip().split('\n')[0] if subprocess.call(['where', 'ffprobe'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) == 0 else None
|
||||
ffplay_path = subprocess.check_output(['where', 'ffplay'], text=True).strip().split('\n')[0] if subprocess.call(['where', 'ffplay'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) == 0 else None
|
||||
|
||||
if ffmpeg_path and ffprobe_path:
|
||||
return ffmpeg_path, ffprobe_path
|
||||
|
||||
# Fallback to which/shutil method for Unix-like systems
|
||||
ffmpeg_path = shutil.which('ffmpeg')
|
||||
ffprobe_path = shutil.which('ffprobe')
|
||||
|
||||
if ffmpeg_path and ffprobe_path:
|
||||
return ffmpeg_path, ffprobe_path
|
||||
if all([ffmpeg_path, ffprobe_path, ffplay_path]):
|
||||
return ffmpeg_path, ffprobe_path, ffplay_path
|
||||
else:
|
||||
ffmpeg_path = shutil.which('ffmpeg')
|
||||
ffprobe_path = shutil.which('ffprobe')
|
||||
ffplay_path = shutil.which('ffplay')
|
||||
|
||||
if all([ffmpeg_path, ffprobe_path, ffplay_path]):
|
||||
return ffmpeg_path, ffprobe_path, ffplay_path
|
||||
|
||||
downloader = FFMPEGDownloader()
|
||||
return downloader.download()
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Error checking FFmpeg: {e}")
|
||||
return None, None
|
||||
return None, None, None
|
@ -311,6 +311,7 @@ class OsSummary:
|
||||
def __init__(self):
|
||||
self.ffmpeg_path = None
|
||||
self.ffprobe_path = None
|
||||
self.ffplay_path = None
|
||||
|
||||
def get_executable_version(self, command: list):
|
||||
"""
|
||||
@ -462,7 +463,7 @@ class OsSummary:
|
||||
|
||||
# Locate ffmpeg from bin installation
|
||||
if self.ffmpeg_path is None or self.ffprobe_path is None:
|
||||
self.ffmpeg_path, self.ffprobe_path = check_ffmpeg()
|
||||
self.ffmpeg_path, self.ffprobe_path, self.ffplay_path = check_ffmpeg()
|
||||
|
||||
if self.ffmpeg_path is None or self.ffprobe_path is None:
|
||||
console.log("[red]Cant locate ffmpeg or ffprobe")
|
||||
|
@ -17,7 +17,6 @@ from StreamingCommunity.Util.console import console, msg
|
||||
from StreamingCommunity.Util._jsonConfig import config_manager
|
||||
from StreamingCommunity.Upload.update import update as git_update
|
||||
from StreamingCommunity.Util.os import os_summary
|
||||
from StreamingCommunity.Lib.TMBD import tmdb
|
||||
from StreamingCommunity.Util.logger import Logger
|
||||
|
||||
|
||||
|
@ -10,6 +10,8 @@ sys.path.append(src_path)
|
||||
|
||||
# Import
|
||||
from StreamingCommunity.Util.message import start_message
|
||||
from StreamingCommunity.Util.os import os_summary
|
||||
os_summary.get_system_summary()
|
||||
from StreamingCommunity.Util.logger import Logger
|
||||
from StreamingCommunity.Lib.Downloader import HLS_Downloader
|
||||
|
||||
@ -19,5 +21,5 @@ start_message()
|
||||
logger = Logger()
|
||||
print("Return: ", HLS_Downloader(
|
||||
output_filename="test.mp4",
|
||||
m3u8_index=""
|
||||
m3u8_playlist="https://acdn.ak-stream-videoplatform.sky.it/hls/2024/11/21/968275/master.m3u8"
|
||||
).start())
|
@ -18,6 +18,6 @@ from StreamingCommunity.Lib.Downloader import MP4_downloader
|
||||
start_message()
|
||||
logger = Logger()
|
||||
print("Return: ", MP4_downloader(
|
||||
url="",
|
||||
url="https://148-251-75-109.top/Getintopc.com/IDA_Pro_2020.mp4",
|
||||
path=r".\Video\undefined.mp4"
|
||||
))
|
||||
|
@ -19,7 +19,9 @@ start_message()
|
||||
logger = Logger()
|
||||
manager = TOR_downloader()
|
||||
|
||||
magnet_link = "magnet:?xt="
|
||||
magnet_link = """magnet:?xt=urn:btih:d1257567d7a76d2e40734f561fd175769285ed33&dn=Alien.Romulus.2024.1080p.BluRay.x264-FHC.mkv&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337%2Fannounce&tr=udp%3A%2F%2Ftorrentclub.space%3A6969%2Fannounce&tr=http%3A%2F%2Ftracker.bt4g.com%3A2095%2Fannounce&tr=https%3A%2F%2Ftr.burnabyhighstar.com%3A443%2Fannoun
|
||||
ce&tr=udp%3A%2F%2Ftracker.monitorit4.me%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.0x.tf%3A6969%2Fannounce&tr=http%3A%2F%2Fbt.okmp3.ru%3A2710%2Fannounce&tr=https%3A%2F%2Ftr.doogh.club%3A443%2Fannounce&tr=https%3A%2F%2Ft.btcland.xyz%3A443%2Fannounce&tr=https%3A%2F%2Ftr.fuckbitcoin.xyz%3A443%2Fannounce&tr=http%3A%2F%2Ftrack
|
||||
er.files.fm%3A6969%2Fannounce"""
|
||||
manager.add_magnet_link(magnet_link)
|
||||
manager.start_download()
|
||||
manager.move_downloaded_files()
|
||||
manager.move_downloaded_files(".")
|
||||
|
@ -11,7 +11,7 @@
|
||||
"map_episode_name": "%(tv_name)_S%(season)E%(episode)_%(episode_name)",
|
||||
"config_qbit_tor": {
|
||||
"host": "192.168.1.58",
|
||||
"port": "8080",
|
||||
"port": "7060",
|
||||
"user": "admin",
|
||||
"pass": "adminadmin"
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user