from typing import Callable, Any, Optional from yt_dlp import YoutubeDL from database import get_latest_proxy, delete_proxy, format_proxy_url, mark_proxy_success class ProxyError(Exception): pass def is_proxy_error(error_msg: str) -> bool: proxy_error_keywords = [ 'proxy', 'connection', 'timeout', 'timed out', 'refused', 'unreachable', 'unable to connect', 'network', 'failed to connect', 'connection reset', 'connection aborted', 'read timed out', 'http error 407', # Proxy authentication required 'tunnel connection failed', 'connect to host', ] non_proxy_error_keywords = [ 'requested format is not available', 'format not available', 'no video formats', 'video unavailable', 'private video', 'age restricted', ] error_lower = error_msg.lower() if any(keyword in error_lower for keyword in non_proxy_error_keywords): return False return any(keyword in error_lower for keyword in proxy_error_keywords) def execute_with_proxy_retry( ydl_opts: dict, operation: Callable[[YoutubeDL], Any], max_retries: int = 10 ) -> Any: attempts = 0 last_error = None while attempts < max_retries: attempts += 1 proxy_data = None try: proxy_data = get_latest_proxy() if proxy_data: proxy_url = format_proxy_url(proxy_data) ydl_opts_with_proxy = {**ydl_opts, 'proxy': proxy_url} print(f"Tentativa {attempts}: Usando proxy {proxy_url} (ID: {proxy_data['id']})") else: if attempts == 1: print(f"Tentativa {attempts}: Nenhum proxy disponível, tentando sem proxy") ydl_opts_with_proxy = ydl_opts else: raise ProxyError("Não há mais proxies disponíveis no banco de dados") with YoutubeDL(ydl_opts_with_proxy) as ydl: result = operation(ydl) print(f"Operação concluída com sucesso na tentativa {attempts}") if proxy_data: mark_proxy_success(proxy_data['id']) return result except Exception as e: error_msg = str(e) last_error = e print(f"Erro na tentativa {attempts}: {error_msg}") if is_proxy_error(error_msg): if proxy_data: print(f"Erro identificado como erro de proxy. Removendo proxy ID {proxy_data['id']}") delete_proxy(proxy_data['id']) else: print("Erro de proxy mas nenhum proxy estava sendo usado") continue else: print(f"Erro não é relacionado a proxy, lançando exceção") raise e raise ProxyError( f"Falha após {max_retries} tentativas. Último erro: {last_error}" )