116 lines
3.7 KiB
Python
116 lines
3.7 KiB
Python
"""
|
|
YouTube utilities for channel info, playlist info, and yt-dlp command generation.
|
|
"""
|
|
|
|
import subprocess
|
|
import json
|
|
from pathlib import Path
|
|
from typing import List, Dict, Any, Optional
|
|
|
|
def get_channel_info(channel_url: str, yt_dlp_path: str = "downloader/yt-dlp.exe") -> Dict[str, Any]:
|
|
"""Get channel information using yt-dlp."""
|
|
try:
|
|
cmd = [
|
|
yt_dlp_path,
|
|
"--dump-json",
|
|
"--no-playlist",
|
|
channel_url
|
|
]
|
|
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
|
|
return json.loads(result.stdout)
|
|
except subprocess.CalledProcessError as e:
|
|
print(f"❌ Failed to get channel info: {e}")
|
|
return {}
|
|
|
|
def get_playlist_info(playlist_url: str, yt_dlp_path: str = "downloader/yt-dlp.exe") -> List[Dict[str, Any]]:
|
|
"""Get playlist information using yt-dlp."""
|
|
try:
|
|
cmd = [
|
|
yt_dlp_path,
|
|
"--dump-json",
|
|
"--flat-playlist",
|
|
playlist_url
|
|
]
|
|
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
|
|
videos = []
|
|
for line in result.stdout.strip().split('\n'):
|
|
if line.strip():
|
|
videos.append(json.loads(line))
|
|
return videos
|
|
except subprocess.CalledProcessError as e:
|
|
print(f"❌ Failed to get playlist info: {e}")
|
|
return []
|
|
|
|
def build_yt_dlp_command(
|
|
yt_dlp_path: str,
|
|
video_url: str,
|
|
output_path: Path,
|
|
config: Dict[str, Any],
|
|
additional_args: Optional[List[str]] = None
|
|
) -> List[str]:
|
|
"""
|
|
Build a standardized yt-dlp command with consistent arguments.
|
|
|
|
Args:
|
|
yt_dlp_path: Path to yt-dlp executable
|
|
video_url: YouTube video URL
|
|
output_path: Output file path
|
|
config: Configuration dictionary with download settings
|
|
additional_args: Optional additional arguments to append
|
|
|
|
Returns:
|
|
List of command arguments for subprocess.run
|
|
"""
|
|
cmd = [
|
|
str(yt_dlp_path),
|
|
"--no-check-certificates",
|
|
"--ignore-errors",
|
|
"--no-warnings",
|
|
"-o", str(output_path),
|
|
"-f", config.get("download_settings", {}).get("format", "best[height<=720][ext=mp4]/best[height<=720]/best[ext=mp4]/best"),
|
|
video_url
|
|
]
|
|
|
|
# Add any additional arguments
|
|
if additional_args:
|
|
cmd.extend(additional_args)
|
|
|
|
return cmd
|
|
|
|
def execute_yt_dlp_command(cmd: List[str], timeout: Optional[int] = None) -> subprocess.CompletedProcess:
|
|
"""
|
|
Execute a yt-dlp command with standardized error handling.
|
|
|
|
Args:
|
|
cmd: Command list to execute
|
|
timeout: Optional timeout in seconds
|
|
|
|
Returns:
|
|
CompletedProcess object
|
|
|
|
Raises:
|
|
subprocess.CalledProcessError: If the command fails
|
|
subprocess.TimeoutExpired: If the command times out
|
|
"""
|
|
return subprocess.run(cmd, capture_output=True, text=True, check=True, timeout=timeout)
|
|
|
|
def show_available_formats(video_url: str, yt_dlp_path: str = "downloader/yt-dlp.exe", timeout: int = 30) -> None:
|
|
"""
|
|
Show available formats for a video (debugging utility).
|
|
|
|
Args:
|
|
video_url: YouTube video URL
|
|
yt_dlp_path: Path to yt-dlp executable
|
|
timeout: Timeout in seconds
|
|
"""
|
|
print(f"🔍 Checking available formats for: {video_url}")
|
|
format_cmd = [
|
|
str(yt_dlp_path),
|
|
"--list-formats",
|
|
video_url
|
|
]
|
|
try:
|
|
format_result = subprocess.run(format_cmd, capture_output=True, text=True, timeout=timeout)
|
|
print(f"📋 Available formats:\n{format_result.stdout}")
|
|
except Exception as e:
|
|
print(f"⚠️ Could not check formats: {e}") |