#!/usr/bin/env python3
"""
Test de téléchargement d'une vidéo Instagram avec authentification hybride
"""

import subprocess
import json
import logging
import os
import time
import re
import random
import string
from urllib.parse import urlencode, quote

# Configuration du logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)

def generate_device_id():
    """Génère un ID de device Android aléatoire"""
    # Format: android-XXXXXXXXXXXXXXXX
    random_hex = ''.join(random.choices(string.hexdigits.lower(), k=16))
    return f"android-{random_hex}"

def extract_post_id(url):
    """Extrait l'ID du post Instagram depuis l'URL"""
    patterns = [
        r'instagram\.com/p/([^/]+)',
        r'instagram\.com/reel/([^/]+)',
    ]
    for pattern in patterns:
        match = re.search(pattern, url)
        if match:
            return match.group(1).split('/')[0]
    return None

def get_instagram_session():
    """Récupère une session Instagram valide"""
    device_id = generate_device_id()
    headers = {
        'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 12_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 Instagram 105.0.0.11.118 (iPhone11,8; iOS 12_3_1; en_US; en-US; scale=2.00; 828x1792; 165586599)',
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
        'Accept-Language': 'en-US,en;q=0.5',
        'Accept-Encoding': 'gzip, deflate',
        'X-IG-App-ID': '936619743392459',
        'X-IG-WWW-Claim': '0',
        'X-Requested-With': 'XMLHttpRequest',
        'DNT': '1',
        'Connection': 'keep-alive',
    }
    
    # Première requête pour obtenir les cookies initiaux
    init_cmd = [
        'curl',
        'https://www.instagram.com/web/__mid/',
        '-H', f'User-Agent: {headers["User-Agent"]}',
        '-H', f'Accept: {headers["Accept"]}',
        '-H', f'Accept-Language: {headers["Accept-Language"]}',
        '-H', f'X-IG-App-ID: {headers["X-IG-App-ID"]}',
        '-c', 'instagram_cookies.txt',  # Sauvegarder les cookies
        '-s'
    ]
    
    logger.debug(f"Initialisation de la session...")
    process = subprocess.Popen(init_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    stdout, stderr = process.communicate()
    
    if process.returncode != 0:
        logger.error(f"Erreur lors de l'initialisation: {stderr.decode()}")
        return None
        
    # Seconde requête pour obtenir le csrftoken
    csrf_cmd = [
        'curl',
        'https://www.instagram.com/data/shared_data/',
        '-H', f'User-Agent: {headers["User-Agent"]}',
        '-H', f'Accept: {headers["Accept"]}',
        '-H', f'Accept-Language: {headers["Accept-Language"]}',
        '-H', f'X-IG-App-ID: {headers["X-IG-App-ID"]}',
        '-H', f'X-IG-WWW-Claim: {headers["X-IG-WWW-Claim"]}',
        '-b', 'instagram_cookies.txt',  # Utiliser les cookies
        '-c', 'instagram_cookies.txt',  # Mettre à jour les cookies
        '-s'
    ]
    
    logger.debug(f"Récupération du CSRF token...")
    process = subprocess.Popen(csrf_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    stdout, stderr = process.communicate()
    
    if process.returncode != 0:
        logger.error(f"Erreur lors de la récupération du CSRF: {stderr.decode()}")
        return None
        
    try:
        shared_data = json.loads(stdout)
        csrf_token = shared_data.get('config', {}).get('csrf_token')
        if not csrf_token:
            logger.error("Impossible de trouver le CSRF token")
            return None
            
        return {
            'cookies_file': 'instagram_cookies.txt',
            'csrf_token': csrf_token,
            'device_id': device_id
        }
    except json.JSONDecodeError:
        logger.error("Erreur lors du décodage de la réponse")
        return None

def download_instagram_video(url, output_dir="downloads"):
    """Télécharge une vidéo Instagram en utilisant une authentification hybride"""
    
    logger.info(f"🔄 Téléchargement depuis Instagram: {url}")
    
    # Créer le dossier de téléchargement
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)
    
    # Extraire l'ID du post
    post_id = extract_post_id(url)
    if not post_id:
        logger.error("❌ URL Instagram invalide")
        return None
        
    try:
        # Obtenir une session valide
        session = get_instagram_session()
        if not session:
            logger.error("❌ Impossible d'obtenir une session valide")
            return None
            
        # Headers pour l'API mobile
        headers = {
            'User-Agent': 'Instagram 219.0.0.12.117 Android',
            'Accept': '*/*',
            'Accept-Language': 'en-US',
            'Accept-Encoding': 'gzip, deflate',
            'X-IG-Capabilities': '3brTvw==',
            'X-IG-Connection-Type': 'WIFI',
            'X-IG-App-ID': '936619743392459',
            'X-IG-WWW-Claim': '0',
            'X-CSRFToken': session['csrf_token']
        }
        
        # Requête à l'API mobile avec authentification
        logger.info("Récupération des informations via l'API mobile...")
        api_url = f"https://i.instagram.com/api/v1/media/{post_id}/info/"
        
        api_cmd = [
            'curl',
            api_url,
            '-H', f'User-Agent: {headers["User-Agent"]}',
            '-H', f'Accept: {headers["Accept"]}',
            '-H', f'Accept-Language: {headers["Accept-Language"]}',
            '-H', f'X-IG-App-ID: {headers["X-IG-App-ID"]}',
            '-H', f'X-IG-WWW-Claim: {headers["X-IG-WWW-Claim"]}',
            '-H', f'X-IG-Capabilities: {headers["X-IG-Capabilities"]}',
            '-H', f'X-IG-Connection-Type: {headers["X-IG-Connection-Type"]}',
            '-H', f'X-CSRFToken: {headers["X-CSRFToken"]}',
            '-b', session['cookies_file'],  # Utiliser les cookies
            '--compressed',
            '-s'
        ]
        
        logger.debug(f"Commande API: {' '.join(api_cmd)}")
        
        process = subprocess.Popen(api_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        stdout, stderr = process.communicate()
        
        if process.returncode != 0:
            logger.error(f"❌ Erreur lors de la requête API: {stderr.decode()}")
            return None
            
        logger.debug(f"Réponse API: {stdout.decode()}")
            
        try:
            response_data = json.loads(stdout)
            
            if 'items' not in response_data or not response_data['items']:
                logger.error("❌ Pas de données dans la réponse API")
                # Essayer l'approche web si l'API mobile échoue
                return download_from_web(url, session, headers, output_dir)
                
            media = response_data['items'][0]
            
            if 'video_versions' not in media:
                logger.error("❌ Ce post n'est pas une vidéo")
                return None
                
            # Prendre la meilleure qualité
            video_url = media['video_versions'][0]['url']
            
            return download_video_file(video_url, headers, output_dir)
                
        except json.JSONDecodeError:
            logger.error("❌ Erreur de décodage JSON de la réponse API")
            logger.debug(f"Réponse reçue: {stdout.decode()}")
            # Essayer l'approche web si l'API mobile échoue
            return download_from_web(url, session, headers, output_dir)
            
    except Exception as e:
        logger.error(f"❌ Erreur: {str(e)}")
        return None
    finally:
        # Nettoyer les fichiers temporaires
        if os.path.exists('instagram_cookies.txt'):
            os.remove('instagram_cookies.txt')

def download_from_web(url, session, headers, output_dir):
    """Télécharge la vidéo en utilisant l'approche web classique"""
    
    logger.info("Tentative de téléchargement via l'interface web...")
    
    try:
        web_cmd = [
            'curl',
            url,
            '-H', 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
            '-H', 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
            '-H', 'Accept-Language: en-US,en;q=0.5',
            '-b', session['cookies_file'],
            '--compressed',
            '-s'
        ]
        
        process = subprocess.Popen(web_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        stdout, stderr = process.communicate()
        
        if process.returncode != 0:
            logger.error(f"❌ Erreur lors de la requête web: {stderr.decode()}")
            return None
            
        html_content = stdout.decode()
        
        # Chercher l'URL de la vidéo dans le HTML
        video_match = re.search(r'"video_url":"([^"]+)"', html_content)
        if not video_match:
            logger.error("❌ URL de la vidéo non trouvée dans le HTML")
            return None
            
        video_url = video_match.group(1).replace('\\u0026', '&')
        return download_video_file(video_url, headers, output_dir)
        
    except Exception as e:
        logger.error(f"❌ Erreur lors du téléchargement web: {str(e)}")
        return None

def download_video_file(video_url, headers, output_dir):
    """Télécharge le fichier vidéo depuis l'URL"""
    
    try:
        output_file = os.path.join(output_dir, f"video_{int(time.time())}.mp4")
        logger.info("🔄 Téléchargement de la vidéo...")
        
        download_cmd = [
            'curl',
            video_url,
            '-L',  # Suivre les redirections
            '-o', output_file,
            '-H', f'User-Agent: {headers["User-Agent"]}',
            '-H', 'Accept: */*',
            '--compressed',
            '-s'
        ]
        
        logger.debug(f"Commande de téléchargement: {' '.join(download_cmd)}")
        
        download_process = subprocess.Popen(download_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        stdout, stderr = download_process.communicate()
        
        if download_process.returncode == 0 and os.path.exists(output_file):
            logger.info(f"✅ Vidéo téléchargée: {output_file}")
            return output_file
        else:
            logger.error(f"❌ Erreur lors du téléchargement: {stderr.decode()}")
            return None
            
    except Exception as e:
        logger.error(f"❌ Erreur lors du téléchargement: {str(e)}")
        return None

if __name__ == "__main__":
    url = "https://www.instagram.com/reel/C2_Kh6mPmGl/"
    result = download_instagram_video(url)
    
    if result:
        print(f"\n✅ Vidéo téléchargée avec succès: {result}")
    else:
        print("\n❌ Échec du téléchargement")
