import os
import logging
import subprocess
import tempfile
import uuid
import shutil
import time
import random
import re
import json
import requests
from bs4 import BeautifulSoup
from urllib.parse import urlparse, parse_qs

class VideoDownloader:
    def __init__(self, download_path='downloads', public_path='/var/www/html/downloads', public_url='http://8.215.44.123/downloads'):
        self.download_path = download_path
        self.public_path = public_path
        self.public_url = public_url
        
        # Ensure download directory exists
        os.makedirs(download_path, exist_ok=True)
        
        # Configure logging
        logging.basicConfig(
            format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
            level=logging.INFO
        )
        self.logger = logging.getLogger(__name__)
        
        # User agents for rotation
        self.user_agents = [
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
            'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Safari/605.1.15',
            'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36',
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0',
            'Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1'
        ]
    
    def get_platform(self, url):
        """Determine the platform from the URL"""
        if 'youtube.com' in url or 'youtu.be' in url:
            return 'youtube'
        elif 'facebook.com' in url or 'fb.com' in url or 'fb.watch' in url:
            return 'facebook'
        elif 'instagram.com' in url:
            return 'instagram'
        elif 'tiktok.com' in url:
            return 'tiktok'
        else:
            return 'generic'
    
    def get_random_user_agent(self):
        """Get a random user agent from the list"""
        return random.choice(self.user_agents)
    
    def get_youtube_video_id(self, url):
        """Extract YouTube video ID from URL"""
        if 'youtu.be' in url:
            # Short URL format: https://youtu.be/VIDEO_ID
            path = urlparse(url).path
            return path.strip('/').split('?')[0]
        else:
            # Regular URL format: https://www.youtube.com/watch?v=VIDEO_ID
            parsed_url = urlparse(url)
            query_params = parse_qs(parsed_url.query)
            return query_params.get('v', [''])[0]
    
    def get_instagram_shortcode(self, url):
        """Extract Instagram shortcode from URL"""
        # URL format: https://www.instagram.com/p/SHORTCODE/
        match = re.search(r'instagram\.com/(?:p|reel)/([^/?]+)', url)
        if match:
            return match.group(1)
        return None
    
    def compress_video(self, input_file, target_size_mb=10, output_file=None):
        """Compress video to target size in MB"""
        try:
            self.logger.info(f"Compressing video: {input_file} to target size: {target_size_mb}MB")
            
            # Create output file if not provided
            if output_file is None:
                file_name, file_ext = os.path.splitext(input_file)
                output_file = f"{file_name}_compressed{file_ext}"
            
            # Check if ffmpeg is installed
            try:
                subprocess.run(['ffmpeg', '-version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True)
            except (subprocess.SubprocessError, FileNotFoundError):
                self.logger.error("ffmpeg not found. Please install ffmpeg.")
                return input_file
            
            # Get video duration
            cmd = ['ffprobe', '-v', 'error', '-show_entries', 'format=duration', 
                   '-of', 'default=noprint_wrappers=1:nokey=1', input_file]
            result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
            
            if result.returncode != 0:
                self.logger.error(f"Error getting video duration: {result.stderr}")
                return input_file
                
            duration = float(result.stdout.strip())
            
            # Calculate target bitrate (80% for video, 20% for audio)
            target_size_bits = target_size_mb * 8 * 1024 * 1024
            bitrate = int(target_size_bits / (duration * 1.2))  # 1.2 factor for overhead
            
            # Compress video
            cmd = [
                'ffmpeg', '-i', input_file, 
                '-b:v', str(bitrate), 
                '-maxrate', str(bitrate), 
                '-bufsize', str(bitrate*2),
                '-c:a', 'aac', '-b:a', '128k',  # Compress audio too
                '-y', output_file
            ]
            
            self.logger.info(f"Running ffmpeg command: {' '.join(cmd)}")
            result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            
            if result.returncode != 0:
                self.logger.error(f"Error compressing video: {result.stderr}")
                return input_file
            
            # Verify the compressed file exists and is smaller
            if os.path.exists(output_file):
                original_size = os.path.getsize(input_file) / (1024 * 1024)  # MB
                compressed_size = os.path.getsize(output_file) / (1024 * 1024)  # MB
                
                self.logger.info(f"Original size: {original_size:.2f}MB, Compressed size: {compressed_size:.2f}MB")
                
                if compressed_size < original_size:
                    return output_file
                else:
                    self.logger.warning("Compressed file is not smaller than original. Using original file.")
                    os.remove(output_file)
                    return input_file
            else:
                self.logger.error("Compressed file was not created")
                return input_file
                
        except Exception as e:
            self.logger.error(f"Error in compress_video: {str(e)}")
            return input_file  # Return original file if compression fails
    
    def create_public_download_link(self, file_path, title, expiry_hours=24):
        """Create a public download link for a file"""
        try:
            # Ensure public directory exists
            os.makedirs(self.public_path, exist_ok=True)
            
            # Generate a unique filename to avoid collisions
            file_name, file_ext = os.path.splitext(os.path.basename(file_path))
            unique_id = str(uuid.uuid4())[:8]
            safe_title = ''.join(c if c.isalnum() or c in ['-', '_'] else '_' for c in title)
            public_filename = f"{safe_title}_{unique_id}{file_ext}"
            public_file_path = os.path.join(self.public_path, public_filename)
            
            # Copy the file to the public directory
            shutil.copy2(file_path, public_file_path)
            
            # Generate the public URL
            download_url = f"{self.public_url}/{public_filename}"
            
            # Create a .info file with metadata
            info_file_path = f"{public_file_path}.info"
            with open(info_file_path, 'w') as f:
                f.write(f"Title: {title}\n")
                f.write(f"Original file: {os.path.basename(file_path)}\n")
                f.write(f"Created: {subprocess.check_output(['date']).decode('utf-8')}")
                f.write(f"Expires: After {expiry_hours} hours\n")
            
            # Schedule file deletion (if possible)
            try:
                # Use at command to schedule deletion
                delete_cmd = f"rm -f {public_file_path} {info_file_path}"
                at_time = f"now + {expiry_hours} hours"
                subprocess.run(f'echo "{delete_cmd}" | at {at_time}', shell=True)
                self.logger.info(f"Scheduled deletion of {public_file_path} after {expiry_hours} hours")
            except Exception as e:
                self.logger.warning(f"Could not schedule file deletion: {e}")
            
            return {
                'success': True,
                'url': download_url,
                'file_path': public_file_path,
                'expires_in_hours': expiry_hours
            }
            
        except Exception as e:
            self.logger.error(f"Error creating download link: {str(e)}")
            return {
                'success': False,
                'error': str(e)
            }
    
    def download_with_direct_youtube_api(self, url, audio_only=False):
        """Download YouTube video using direct API approach"""
        try:
            video_id = self.get_youtube_video_id(url)
            if not video_id:
                return {'success': False, 'error': 'Could not extract YouTube video ID'}
            
            self.logger.info(f"Attempting to download YouTube video with ID: {video_id}")
            
            # Try to get video info using y2mate API
            try:
                # Step 1: Get video info
                session = requests.Session()
                session.headers.update({'User-Agent': self.get_random_user_agent()})
                
                analyze_url = 'https://www.y2mate.com/mates/analyze/ajax'
                data = {
                    'url': f'https://www.youtube.com/watch?v={video_id}',
                    'q_auto': 0,
                    'ajax': 1
                }
                
                response = session.post(analyze_url, data=data, timeout=15)
                if response.status_code == 200:
                    analyze_data = response.json()
                    if 'result' in analyze_data:
                        # Parse the HTML response to get video title and k parameter
                        soup = BeautifulSoup(analyze_data['result'], 'html.parser')
                        title_elem = soup.select_one('.caption > b')
                        title = title_elem.text.strip() if title_elem else f'YouTube Video {video_id}'
                        
                        # Find the appropriate format button
                        if audio_only:
                            format_btn = soup.select_one('a[data-ftype="mp3"][data-fquality="128"]')
                        else:
                            format_btn = soup.select_one('a[data-ftype="mp4"][data-fquality="720p"]')
                            if not format_btn:
                                format_btn = soup.select_one('a[data-ftype="mp4"][data-fquality="360p"]')
                        
                        if format_btn:
                            k = format_btn.get('data-id')
                            if k:
                                # Step 2: Convert and get download link
                                convert_url = 'https://www.y2mate.com/mates/convert'
                                convert_data = {
                                    'type': 'youtube',
                                    '_id': k,
                                    'v_id': video_id,
                                    'ajax': '1',
                                    'token': '',
                                    'ftype': 'mp3' if audio_only else 'mp4',
                                    'fquality': '128' if audio_only else '720p'
                                }
                                
                                response = session.post(convert_url, data=convert_data, timeout=15)
                                if response.status_code == 200:
                                    convert_data = response.json()
                                    if 'result' in convert_data:
                                        # Parse the HTML response to get download link
                                        soup = BeautifulSoup(convert_data['result'], 'html.parser')
                                        download_link = soup.select_one('a.btn-success')
                                        
                                        if download_link and download_link.get('href'):
                                            download_url = download_link['href']
                                            
                                            # Step 3: Download the file
                                            ext = 'mp3' if audio_only else 'mp4'
                                            output_file = os.path.join(self.download_path, f"youtube_{video_id}.{ext}")
                                            
                                            response = session.get(download_url, stream=True, timeout=30)
                                            if response.status_code == 200:
                                                with open(output_file, 'wb') as f:
                                                    for chunk in response.iter_content(chunk_size=8192):
                                                        f.write(chunk)
                                                
                                                return {
                                                    'success': True,
                                                    'file_path': output_file,
                                                    'title': title,
                                                    'format': ext
                                                }
            except Exception as e:
                self.logger.warning(f"Y2mate approach failed: {str(e)}")
            
            # Try using savefrom.net API
            try:
                api_url = 'https://api.savefrom.net/api/convert'
                headers = {
                    'User-Agent': self.get_random_user_agent(),
                    'Content-Type': 'application/json',
                    'Accept': 'application/json'
                }
                
                data = {
                    'url': url,
                    'extension': 'mp3' if audio_only else 'mp4'
                }
                
                response = requests.post(api_url, headers=headers, json=data, timeout=20)
                if response.status_code == 200:
                    api_data = response.json()
                    if 'url' in api_data and api_data['url']:
                        download_url = api_data['url']
                        title = api_data.get('title', f'YouTube Video {video_id}')
                        
                        # Download the file
                        ext = 'mp3' if audio_only else 'mp4'
                        output_file = os.path.join(self.download_path, f"youtube_{video_id}.{ext}")
                        
                        response = requests.get(download_url, headers={'User-Agent': self.get_random_user_agent()}, stream=True, timeout=30)
                        if response.status_code == 200:
                            with open(output_file, 'wb') as f:
                                for chunk in response.iter_content(chunk_size=8192):
                                    f.write(chunk)
                            
                            return {
                                'success': True,
                                'file_path': output_file,
                                'title': title,
                                'format': ext
                            }
            except Exception as e:
                self.logger.warning(f"Savefrom approach failed: {str(e)}")
            
            # If all direct methods fail, try using yt-dlp
            return self.download_with_ytdlp(url, audio_only)
            
        except Exception as e:
            self.logger.error(f"Error in direct YouTube API download: {str(e)}")
            # Try fallback to yt-dlp
            return self.download_with_ytdlp(url, audio_only)
    
    def download_with_direct_instagram_api(self, url, audio_only=False):
        """Download Instagram video using direct API approach"""
        try:
            shortcode = self.get_instagram_shortcode(url)
            if not shortcode:
                return {'success': False, 'error': 'Could not extract Instagram shortcode'}
            
            self.logger.info(f"Attempting to download Instagram post with shortcode: {shortcode}")
            
            # Try using sssinstagram API
            try:
                api_url = 'https://sssinstagram.com/api/instagram/media'
                headers = {
                    'User-Agent': self.get_random_user_agent(),
                    'Content-Type': 'application/x-www-form-urlencoded',
                    'Accept': 'application/json',
                    'Origin': 'https://sssinstagram.com',
                    'Referer': 'https://sssinstagram.com/en'
                }
                
                data = {
                    'url': url
                }
                
                response = requests.post(api_url, headers=headers, data=data, timeout=20)
                if response.status_code == 200:
                    api_data = response.json()
                    if 'medias' in api_data and api_data['medias']:
                        # Find video URL
                        video_url = None
                        for media in api_data['medias']:
                            if media.get('type') == 'video':
                                video_url = media.get('url')
                                break
                        
                        if video_url:
                            title = api_data.get('title', f'Instagram Post {shortcode}')
                            
                            # Download the file
                            ext = 'mp3' if audio_only else 'mp4'
                            output_file = os.path.join(self.download_path, f"instagram_{shortcode}.{ext}")
                            
                            response = requests.get(video_url, headers={'User-Agent': self.get_random_user_agent()}, stream=True, timeout=30)
                            if response.status_code == 200:
                                with open(output_file, 'wb') as f:
                                    for chunk in response.iter_content(chunk_size=8192):
                                        f.write(chunk)
                                
                                # Convert to mp3 if audio_only
                                if audio_only:
                                    mp3_file = os.path.join(self.download_path, f"instagram_{shortcode}.mp3")
                                    cmd = [
                                        'ffmpeg', '-i', output_file, 
                                        '-vn', '-ab', '128k', '-ar', '44100', '-y', mp3_file
                                    ]
                                    subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                                    os.remove(output_file)
                                    output_file = mp3_file
                                    ext = 'mp3'
                                
                                return {
                                    'success': True,
                                    'file_path': output_file,
                                    'title': title,
                                    'format': ext
                                }
            except Exception as e:
                self.logger.warning(f"sssinstagram approach failed: {str(e)}")
            
            # Try using savefrom.net API
            try:
                api_url = 'https://api.savefrom.net/api/convert'
                headers = {
                    'User-Agent': self.get_random_user_agent(),
                    'Content-Type': 'application/json',
                    'Accept': 'application/json'
                }
                
                data = {
                    'url': url,
                    'extension': 'mp3' if audio_only else 'mp4'
                }
                
                response = requests.post(api_url, headers=headers, json=data, timeout=20)
                if response.status_code == 200:
                    api_data = response.json()
                    if 'url' in api_data and api_data['url']:
                        download_url = api_data['url']
                        title = api_data.get('title', f'Instagram Post {shortcode}')
                        
                        # Download the file
                        ext = 'mp3' if audio_only else 'mp4'
                        output_file = os.path.join(self.download_path, f"instagram_{shortcode}.{ext}")
                        
                        response = requests.get(download_url, headers={'User-Agent': self.get_random_user_agent()}, stream=True, timeout=30)
                        if response.status_code == 200:
                            with open(output_file, 'wb') as f:
                                for chunk in response.iter_content(chunk_size=8192):
                                    f.write(chunk)
                            
                            # Convert to mp3 if audio_only
                            if audio_only:
                                mp3_file = os.path.join(self.download_path, f"instagram_{shortcode}.mp3")
                                cmd = [
                                    'ffmpeg', '-i', output_file, 
                                    '-vn', '-ab', '128k', '-ar', '44100', '-y', mp3_file
                                ]
                                subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                                os.remove(output_file)
                                output_file = mp3_file
                                ext = 'mp3'
                            
                            return {
                                'success': True,
                                'file_path': output_file,
                                'title': title,
                                'format': ext
                            }
            except Exception as e:
                self.logger.warning(f"Savefrom approach failed: {str(e)}")
            
            # If all direct methods fail, try using yt-dlp with cookies
            return self.download_with_ytdlp_instagram(url, audio_only)
            
        except Exception as e:
            self.logger.error(f"Error in direct Instagram API download: {str(e)}")
            # Try fallback to yt-dlp
            return self.download_with_ytdlp(url, audio_only)
    
    def download_with_ytdlp_instagram(self, url, audio_only=False):
        """Download Instagram video using yt-dlp with cookies"""
        try:
            import yt_dlp
            
            # Create a temporary cookies file with dummy Instagram cookies
            # This helps bypass some restrictions
            cookies_content = """# Netscape HTTP Cookie File
.instagram.com	TRUE	/	TRUE	1798869816	csrftoken	dummy_csrftoken
.instagram.com	TRUE	/	TRUE	1798869816	ds_user_id	dummy_user_id
.instagram.com	TRUE	/	TRUE	1798869816	ig_did	dummy_ig_did
.instagram.com	TRUE	/	TRUE	1798869816	mid	dummy_mid
.instagram.com	TRUE	/	TRUE	1798869816	sessionid	dummy_sessionid
"""
            cookies_file = os.path.join(tempfile.gettempdir(), 'instagram_cookies.txt')
            with open(cookies_file, 'w') as f:
                f.write(cookies_content)
            
            shortcode = self.get_instagram_shortcode(url)
            filename = f"instagram_{shortcode if shortcode else os.urandom(4).hex()}"
            output_template = os.path.join(self.download_path, filename)
            
            # Enhanced yt-dlp options with Instagram-specific settings
            ydl_opts = {
                'outtmpl': output_template + '.%(ext)s',
                'quiet': False,
                'no_warnings': False,
                'verbose': True,
                'ignoreerrors': True,
                'nocheckcertificate': True,
                'geo_bypass': True,
                'geo_bypass_country': 'US',
                'retries': 15,
                'fragment_retries': 15,
                'socket_timeout': 60,
                'cookiefile': cookies_file,  # Use the temporary cookies file
                'http_headers': {
                    'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1',
                    'Accept-Language': 'en-US,en;q=0.9',
                    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
                    'Referer': 'https://www.instagram.com/',
                    'Origin': 'https://www.instagram.com',
                },
                'format': 'bestaudio/best' if audio_only else 'best',
            }
            
            if audio_only:
                ydl_opts.update({
                    'postprocessors': [{
                        'key': 'FFmpegExtractAudio',
                        'preferredcodec': 'mp3',
                        'preferredquality': '192',
                    }],
                })
                final_ext = 'mp3'
            else:
                final_ext = 'mp4'
            
            with yt_dlp.YoutubeDL(ydl_opts) as ydl:
                self.logger.info(f"Attempting to download {url} with yt-dlp and cookies")
                info = ydl.extract_info(url, download=True)
                
                # Clean up the temporary cookies file
                try:
                    os.remove(cookies_file)
                except:
                    pass
                
                if not info:
                    return {'success': False, 'error': 'Failed to extract video information with yt-dlp'}
                
                if 'entries' in info:  # Playlist
                    if not info['entries']:
                        return {'success': False, 'error': 'Empty playlist or all videos failed'}
                    info = info['entries'][0]
                
                # Get the actual file extension
                if not audio_only:
                    final_ext = info.get('ext', 'mp4')
                
                title = info.get('title', 'Instagram Video')
                file_path = f"{output_template}.{final_ext}"
                
                # Verify file exists
                if not os.path.exists(file_path):
                    # Try to find the actual file
                    possible_files = [f for f in os.listdir(self.download_path) if f.startswith(filename)]
                    if possible_files:
                        file_path = os.path.join(self.download_path, possible_files[0])
                    else:
                        return {'success': False, 'error': 'Downloaded file not found'}
                
                return {
                    'success': True, 
                    'file_path': file_path, 
                    'title': title, 
                    'format': final_ext
                }
        except Exception as e:
            self.logger.error(f"Error in Instagram yt-dlp download: {str(e)}")
            return {'success': False, 'error': str(e)}
    
    def download_with_ytdlp(self, url, audio_only=False):
        """Download video using yt-dlp with improved error handling"""
        try:
            import yt_dlp
            
            platform = self.get_platform(url)
            filename = f"{platform}_{os.urandom(4).hex()}"
            output_template = os.path.join(self.download_path, filename)
            
            # Add random delay to avoid rate limiting
            time.sleep(random.uniform(0.5, 2))
            
            # Enhanced yt-dlp options with better error handling
            ydl_opts = {
                'outtmpl': output_template + '.%(ext)s',
                'quiet': False,
                'no_warnings': False,
                'verbose': True,
                'ignoreerrors': True,
                'nocheckcertificate': True,
                'geo_bypass': True,
                'geo_bypass_country': 'US',
                'retries': 15,
                'fragment_retries': 15,
                'socket_timeout': 60,
                'http_headers': {
                    'User-Agent': self.get_random_user_agent(),
                    'Accept-Language': 'en-US,en;q=0.9',
                    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
                    'Referer': 'https://www.google.com/',
                },
                'external_downloader_args': ['--max-retries', '10'],
                'hls_prefer_native': False,
                'hls_use_mpegts': True,
            }
            
            # Add YouTube-specific options
            if platform == 'youtube':
                ydl_opts.update({
                    'format': 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best',
                    'merge_output_format': 'mp4',
                    'noplaylist': True,
                    'extractor_args': {
                        'youtube': {
                            'player_client': ['android', 'web', 'tv_embedded', 'ios'],
                            'skip': ['dash', 'hls'],
                        }
                    },
                    'extractor_retries': 10,
                    'youtube_include_dash_manifest': False,
                    'prefer_insecure': True,
                    'force_generic_extractor': False,
                })
            
            if audio_only:
                ydl_opts.update({
                    'format': 'bestaudio/best',
                    'postprocessors': [{
                        'key': 'FFmpegExtractAudio',
                        'preferredcodec': 'mp3',
                        'preferredquality': '192',
                    }],
                })
                final_ext = 'mp3'
            else:
                if platform != 'youtube':
                    ydl_opts.update({
                        'format': 'best',
                    })
                final_ext = 'mp4'
            
            # Try with multiple configurations if needed
            error_messages = []
            
            # First attempt with standard configuration
            try:
                with yt_dlp.YoutubeDL(ydl_opts) as ydl:
                    self.logger.info(f"Attempting to download {url} with yt-dlp (attempt 1)")
                    info = ydl.extract_info(url, download=True)
                    
                    if info:
                        # Success on first attempt
                        if 'entries' in info:  # Playlist
                            if not info['entries']:
                                raise Exception("Empty playlist or all videos failed")
                            info = info['entries'][0]
                        
                        # Get the actual file extension
                        if not audio_only:
                            final_ext = info.get('ext', 'mp4')
                        
                        title = info.get('title', 'Video')
                        file_path = f"{output_template}.{final_ext}"
                        
                        # Verify file exists
                        if not os.path.exists(file_path):
                            # Try to find the actual file
                            possible_files = [f for f in os.listdir(self.download_path) if f.startswith(filename)]
                            if possible_files:
                                file_path = os.path.join(self.download_path, possible_files[0])
                            else:
                                raise Exception("Downloaded file not found")
                        
                        return {
                            'success': True, 
                            'file_path': file_path, 
                            'title': title, 
                            'format': final_ext
                        }
            except Exception as e:
                error_messages.append(f"Attempt 1 failed: {str(e)}")
                self.logger.warning(f"First download attempt failed: {str(e)}")
            
            # Second attempt with different options
            try:
                # Modify options for second attempt
                second_attempt_opts = ydl_opts.copy()
                second_attempt_opts.update({
                    'format': 'best',
                    'force_generic_extractor': True,
                })
                
                with yt_dlp.YoutubeDL(second_attempt_opts) as ydl:
                    self.logger.info(f"Attempting to download {url} with yt-dlp (attempt 2)")
                    info = ydl.extract_info(url, download=True)
                    
                    if info:
                        # Success on second attempt
                        if 'entries' in info:  # Playlist
                            if not info['entries']:
                                raise Exception("Empty playlist or all videos failed")
                            info = info['entries'][0]
                        
                        # Get the actual file extension
                        if not audio_only:
                            final_ext = info.get('ext', 'mp4')
                        
                        title = info.get('title', 'Video')
                        file_path = f"{output_template}.{final_ext}"
                        
                        # Verify file exists
                        if not os.path.exists(file_path):
                            # Try to find the actual file
                            possible_files = [f for f in os.listdir(self.download_path) if f.startswith(filename)]
                            if possible_files:
                                file_path = os.path.join(self.download_path, possible_files[0])
                            else:
                                raise Exception("Downloaded file not found")
                        
                        return {
                            'success': True, 
                            'file_path': file_path, 
                            'title': title, 
                            'format': final_ext
                        }
            except Exception as e:
                error_messages.append(f"Attempt 2 failed: {str(e)}")
                self.logger.warning(f"Second download attempt failed: {str(e)}")
            
            # If we get here, all attempts failed
            error_summary = "; ".join(error_messages)
            self.logger.error(f"All download attempts failed: {error_summary}")
            return {'success': False, 'error': f"Failed to extract video information after multiple attempts: {error_summary}"}
            
        except Exception as e:
            self.logger.error(f"Error in download_with_ytdlp: {str(e)}")
            return {'success': False, 'error': str(e)}
    
    def download(self, url, audio_only=False, compress=True, target_size_mb=10):
        """Main download method with multiple fallback options"""
        self.logger.info(f"Starting download for {url}, audio_only={audio_only}, compress={compress}")
        platform = self.get_platform(url)
        self.logger.info(f"Detected platform: {platform}")
        
        # Try platform-specific direct methods first
        if platform == 'youtube':
            result = self.download_with_direct_youtube_api(url, audio_only)
        elif platform == 'instagram':
            result = self.download_with_direct_instagram_api(url, audio_only)
        else:
            # For other platforms, try yt-dlp
            result = self.download_with_ytdlp(url, audio_only)
        
        # If download was successful and it's a video (not audio) and compression is enabled
        if result['success'] and not audio_only and compress:
            file_path = result['file_path']
            file_size_mb = os.path.getsize(file_path) / (1024 * 1024)
            
            # Only compress if file is larger than target size
            if file_size_mb > target_size_mb:
                self.logger.info(f"File size ({file_size_mb:.2f}MB) exceeds target size ({target_size_mb}MB). Compressing...")
                compressed_path = self.compress_video(file_path, target_size_mb)
                
                # Update file path if compression was successful
                if compressed_path != file_path:
                    result['file_path'] = compressed_path
                    result['compressed'] = True
                    # Get new file size
                    new_size_mb = os.path.getsize(compressed_path) / (1024 * 1024)
                    self.logger.info(f"Compression complete. New size: {new_size_mb:.2f}MB")
                else:
                    result['compressed'] = False
            else:
                self.logger.info(f"File size ({file_size_mb:.2f}MB) is already below target size ({target_size_mb}MB). Skipping compression.")
                result['compressed'] = False
        
        return result
