feat: Implement GUI and standalone executable
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
import yt_dlp
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
import subprocess
|
||||
import re
|
||||
import time
|
||||
|
||||
def download_video(url, output_dir=None):
|
||||
def download_video(url, output_dir=None, cookies_from_browser=None):
|
||||
"""Downloads a video from the given URL to a temporary location or specified output directory.
|
||||
|
||||
Args:
|
||||
@@ -13,59 +15,66 @@ def download_video(url, output_dir=None):
|
||||
Returns:
|
||||
str: The absolute path to the downloaded video file, or None if download fails.
|
||||
"""
|
||||
if output_dir and not os.path.isdir(output_dir):
|
||||
if output_dir is None:
|
||||
output_dir = os.getcwd()
|
||||
|
||||
if not os.path.isdir(output_dir):
|
||||
print(f"Error: Output directory '{output_dir}' for download does not exist or is not a directory.", file=sys.stderr)
|
||||
return None
|
||||
|
||||
temp_dir = None
|
||||
if not output_dir:
|
||||
temp_dir = tempfile.TemporaryDirectory() # Create a temporary directory
|
||||
output_dir = temp_dir.name
|
||||
# Construct yt-dlp command
|
||||
download_filename = "yt_dlp_downloaded_video.mp4"
|
||||
yt_dlp_command = [
|
||||
"yt-dlp",
|
||||
"--format", "bestvideo[ext!=webm]+bestaudio[ext!=webm]/best[ext!=webm]", # Prioritize non-webm formats
|
||||
"--output", os.path.join(output_dir, download_filename),
|
||||
"--no-playlist", # Only download single video, not entire playlist
|
||||
"--quiet",
|
||||
"--no-warnings",
|
||||
url
|
||||
]
|
||||
|
||||
ydl_opts = {
|
||||
'format': 'bestvideo[ext!=webm]+bestaudio[ext!=webm]/best[ext!=webm]', # Prioritize non-webm formats
|
||||
'outtmpl': os.path.join(output_dir, '%(title)s.%(ext)s'),
|
||||
'noplaylist': True, # Only download single video, not entire playlist
|
||||
'progress_hooks': [lambda d: sys.stdout.write(f"Downloading: {d['filename']} - {d['status']}" + '\r') if d['status'] == 'downloading' else None],
|
||||
'postprocessors': [{
|
||||
'key': 'FFmpegVideoConvertor',
|
||||
'preferedformat': 'mp4',
|
||||
}],
|
||||
'quiet': True, # Suppress yt-dlp output unless error
|
||||
'no_warnings': True,
|
||||
}
|
||||
if cookies_from_browser and cookies_from_browser != "none":
|
||||
yt_dlp_command.extend(["--cookies-from-browser", cookies_from_browser])
|
||||
|
||||
downloaded_file_path = None
|
||||
try:
|
||||
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
|
||||
info_dict = ydl.extract_info(url, download=True)
|
||||
downloaded_file_path = ydl.prepare_filename(info_dict)
|
||||
# yt-dlp might return a path with a different extension if format conversion happened
|
||||
# We need to find the actual downloaded file
|
||||
base, ext = os.path.splitext(downloaded_file_path)
|
||||
if not os.path.exists(downloaded_file_path):
|
||||
# Try common extensions if the exact path isn't found
|
||||
for common_ext in ['.mp4', '.mkv', '.webm', '.flv']:
|
||||
if os.path.exists(base + common_ext):
|
||||
downloaded_file_path = base + common_ext
|
||||
break
|
||||
|
||||
if not os.path.exists(downloaded_file_path):
|
||||
print(f"Error: Downloaded file not found at expected path: {downloaded_file_path}", file=sys.stderr)
|
||||
return None
|
||||
# print(f"Executing yt-dlp command: {' '.join(yt_dlp_command)}", file=sys.stderr)
|
||||
process = subprocess.run(
|
||||
yt_dlp_command,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True
|
||||
)
|
||||
# print(f"DEBUG: yt-dlp stdout: {process.stdout}", file=sys.stderr)
|
||||
# print(f"DEBUG: yt-dlp stderr: {process.stderr}", file=sys.stderr)
|
||||
|
||||
except yt_dlp.utils.DownloadError as e:
|
||||
print(f"Error downloading video: {e}", file=sys.stderr)
|
||||
# The downloaded file path is now explicitly set
|
||||
downloaded_file_path = os.path.join(output_dir, download_filename)
|
||||
|
||||
# print(f"DEBUG: Parsed downloaded_file_path: {downloaded_file_path}", file=sys.stderr)
|
||||
|
||||
# Add retry logic for file existence
|
||||
max_retries = 5
|
||||
retry_delay = 1 # seconds
|
||||
for i in range(max_retries):
|
||||
if downloaded_file_path and os.path.exists(downloaded_file_path):
|
||||
break
|
||||
# print(f"DEBUG: Waiting for downloaded file to appear... (Attempt {i+1}/{max_retries})", file=sys.stderr)
|
||||
time.sleep(retry_delay)
|
||||
else:
|
||||
print(f"Error: Downloaded file not found at expected path after {max_retries} retries: {downloaded_file_path}", file=sys.stderr)
|
||||
return None
|
||||
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"Error running yt-dlp: {e}", file=sys.stderr)
|
||||
print(f"yt-dlp Stderr: {e.stderr}", file=sys.stderr)
|
||||
return None
|
||||
except FileNotFoundError:
|
||||
print("Error: yt-dlp not found. Please ensure yt-dlp is installed and in your PATH.", file=sys.stderr)
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"An unexpected error occurred during download: {e}", file=sys.stderr)
|
||||
return None
|
||||
finally:
|
||||
if temp_dir: # Clean up temporary directory if it was created
|
||||
# The file might have been moved by yt-dlp, so we only clean up if it's empty
|
||||
if not os.listdir(temp_dir.name):
|
||||
temp_dir.cleanup()
|
||||
else:
|
||||
print(f"Warning: Temporary directory {temp_dir.name} not empty, not cleaning up automatically.", file=sys.stderr)
|
||||
|
||||
return downloaded_file_path
|
||||
return downloaded_file_path
|
||||
Reference in New Issue
Block a user