mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-03-09 15:40:26 +00:00
151 lines
No EOL
5.9 KiB
Python
151 lines
No EOL
5.9 KiB
Python
import aria2p
|
|
from aria2p.client import ClientException as DownloadNotFound
|
|
|
|
class HttpMultiLinkDownloader:
|
|
def __init__(self):
|
|
self.downloads = []
|
|
self.completed_downloads = []
|
|
self.total_size = None
|
|
self.aria2 = aria2p.API(
|
|
aria2p.Client(
|
|
host="http://localhost",
|
|
port=6800,
|
|
secret=""
|
|
)
|
|
)
|
|
|
|
def start_download(self, urls: list[str], save_path: str, header: str = None, out: str = None, total_size: int = None):
|
|
"""Add multiple URLs to download queue with same options"""
|
|
options = {"dir": save_path}
|
|
if header:
|
|
options["header"] = header
|
|
if out:
|
|
options["out"] = out
|
|
|
|
# Clear any existing downloads first
|
|
self.cancel_download()
|
|
self.completed_downloads = []
|
|
self.total_size = total_size
|
|
|
|
for url in urls:
|
|
try:
|
|
added_downloads = self.aria2.add(url, options=options)
|
|
self.downloads.extend(added_downloads)
|
|
except Exception as e:
|
|
print(f"Error adding download for URL {url}: {str(e)}")
|
|
|
|
def pause_download(self):
|
|
"""Pause all active downloads"""
|
|
if self.downloads:
|
|
try:
|
|
self.aria2.pause(self.downloads)
|
|
except Exception as e:
|
|
print(f"Error pausing downloads: {str(e)}")
|
|
|
|
def cancel_download(self):
|
|
"""Cancel and remove all downloads"""
|
|
if self.downloads:
|
|
try:
|
|
# First try to stop the downloads
|
|
self.aria2.remove(self.downloads)
|
|
except Exception as e:
|
|
print(f"Error removing downloads: {str(e)}")
|
|
finally:
|
|
# Clear the downloads list regardless of success/failure
|
|
self.downloads = []
|
|
self.completed_downloads = []
|
|
|
|
def get_download_status(self):
|
|
"""Get status for all tracked downloads, auto-remove completed/failed ones"""
|
|
if not self.downloads and not self.completed_downloads:
|
|
return []
|
|
|
|
total_completed = 0
|
|
current_download_speed = 0
|
|
active_downloads = []
|
|
to_remove = []
|
|
|
|
# First calculate sizes from completed downloads
|
|
for completed in self.completed_downloads:
|
|
total_completed += completed['size']
|
|
|
|
# Then check active downloads
|
|
for download in self.downloads:
|
|
try:
|
|
current_download = self.aria2.get_download(download.gid)
|
|
|
|
# Skip downloads that are not properly initialized
|
|
if not current_download or not current_download.files:
|
|
to_remove.append(download)
|
|
continue
|
|
|
|
# Add to completed size and speed calculations
|
|
total_completed += current_download.completed_length
|
|
current_download_speed += current_download.download_speed
|
|
|
|
# If download is complete, move it to completed_downloads
|
|
if current_download.status == 'complete':
|
|
self.completed_downloads.append({
|
|
'name': current_download.name,
|
|
'size': current_download.total_length
|
|
})
|
|
to_remove.append(download)
|
|
else:
|
|
active_downloads.append({
|
|
'name': current_download.name,
|
|
'size': current_download.total_length,
|
|
'completed': current_download.completed_length,
|
|
'speed': current_download.download_speed
|
|
})
|
|
|
|
except DownloadNotFound:
|
|
to_remove.append(download)
|
|
continue
|
|
except Exception as e:
|
|
print(f"Error getting download status: {str(e)}")
|
|
continue
|
|
|
|
# Clean up completed/removed downloads from active list
|
|
for download in to_remove:
|
|
try:
|
|
if download in self.downloads:
|
|
self.downloads.remove(download)
|
|
except ValueError:
|
|
pass
|
|
|
|
# Return aggregate status
|
|
if self.total_size or active_downloads or self.completed_downloads:
|
|
# Use the first active download's name as the folder name, or completed if none active
|
|
folder_name = None
|
|
if active_downloads:
|
|
folder_name = active_downloads[0]['name']
|
|
elif self.completed_downloads:
|
|
folder_name = self.completed_downloads[0]['name']
|
|
|
|
if folder_name and '/' in folder_name:
|
|
folder_name = folder_name.split('/')[0]
|
|
|
|
# Use provided total size if available, otherwise sum from downloads
|
|
total_size = self.total_size
|
|
if not total_size:
|
|
total_size = sum(d['size'] for d in active_downloads) + sum(d['size'] for d in self.completed_downloads)
|
|
|
|
# Calculate completion status based on total downloaded vs total size
|
|
is_complete = len(active_downloads) == 0 and total_completed >= (total_size * 0.99) # Allow 1% margin for size differences
|
|
|
|
# If all downloads are complete, clear the completed_downloads list to prevent status updates
|
|
if is_complete:
|
|
self.completed_downloads = []
|
|
|
|
return [{
|
|
'folderName': folder_name,
|
|
'fileSize': total_size,
|
|
'progress': total_completed / total_size if total_size > 0 else 0,
|
|
'downloadSpeed': current_download_speed,
|
|
'numPeers': 0,
|
|
'numSeeds': 0,
|
|
'status': 'complete' if is_complete else 'active',
|
|
'bytesDownloaded': total_completed,
|
|
}]
|
|
|
|
return [] |