import os import re import requests USER_AGENT = "VLC/3.0.9 LibVLC/3.0.9" HEADERS = {'User-Agent': USER_AGENT} def sanitize_filename(name): return re.sub(r'[\\/*?:\"<>|]', "", name).strip() def aria2c_exists(): return os.path.exists("./aria2c") or os.path.exists("./aria2c.exe") def get_remote_file_size(url): try: with requests.head(url, headers=HEADERS, timeout=10) as head: head.raise_for_status() content_length = head.headers.get('content-length') return int(content_length) if content_length else 0 except Exception: return 0 def download_with_aria2c(url, dest_path, max_connections=1): import subprocess os.makedirs(os.path.dirname(dest_path), exist_ok=True) remote_size = get_remote_file_size(url) if os.path.exists(dest_path): local_size = os.path.getsize(dest_path) if remote_size > 0 and local_size >= remote_size: print(f"✔ Already downloaded: {os.path.basename(dest_path)}") return aria2_bin = "aria2c.exe" if os.name == 'nt' else "./aria2c" cmd = [ aria2_bin, "--dir", os.path.dirname(dest_path), "--out", os.path.basename(dest_path), "--max-connection-per-server=1", "--split=1", "--min-split-size=1M", "--console-log-level=warn", "--allow-overwrite=true", "--header", f"User-Agent: {USER_AGENT}", "--max-concurrent-downloads", str(max_connections), url ] print(f"\n⚡ Fast downloading with aria2c: {os.path.basename(dest_path)}") try: subprocess.run(cmd, check=True) except subprocess.CalledProcessError: print(f"⚠ aria2c failed. Falling back to Python downloader.") download_file_with_progress(url, dest_path, os.path.basename(dest_path)) def download_file_with_progress(url, dest_path, title): resume_byte_pos = 0 local_exists = os.path.exists(dest_path) mode = 'wb' headers = HEADERS.copy() try: with requests.head(url, headers=headers, timeout=10) as head: head.raise_for_status() content_length = head.headers.get('content-length') remote_size = int(content_length) if content_length else 0 accepts_ranges = head.headers.get('accept-ranges', 'none') == 'bytes' except Exception: remote_size = 0 accepts_ranges = False if local_exists: local_size = os.path.getsize(dest_path) if remote_size > 0 and local_size >= remote_size: print(f"✔ Already downloaded: {title}") return elif remote_size > 0 and local_size < remote_size and accepts_ranges: resume_byte_pos = local_size headers['Range'] = f'bytes={resume_byte_pos}-' mode = 'ab' print(f"⏯ Resuming download for {title} at {local_size / (1024 ** 2):.2f} MB") else: print(f"⚠ Restarting download for {title}") mode = 'wb' with requests.get(url, headers=headers, stream=True, timeout=30) as response: response.raise_for_status() total = remote_size downloaded = resume_byte_pos with open(dest_path, mode) as f: for chunk in response.iter_content(chunk_size=1024 * 1024): if chunk: f.write(chunk) downloaded += len(chunk) percent = (downloaded / total * 100) if total else 0 print(f"\rDownloading '{title}': {percent:.2f}%", end='', flush=True) print(f"\n✔ Download complete: {dest_path}")