Add proxymanager

This commit is contained in:
LeoMortari
2025-12-04 22:15:03 -03:00
parent a1eebaf8e1
commit 91f76cea6a
10 changed files with 651 additions and 59 deletions

114
main.py
View File

@@ -8,6 +8,7 @@ from youtube_transcript_api.formatters import SRTFormatter
from youtube_transcript_api._errors import TranscriptsDisabled, NoTranscriptFound
from yt_dlp import YoutubeDL
from utils import extract_video_id, sanitize_title
from proxy_manager import execute_with_proxy_retry, ProxyError
app = FastAPI(
title="YouTube Transcript, Download and Metadata API",
@@ -71,15 +72,17 @@ def get_video_metadata(
'force_generic_extractor': True,
'format': 'best[ext=mp4]/best[ext=webm]/best',
'allow_unplayable_formats': True,
'socket_timeout': 8,
'retries': 0,
}
try:
with YoutubeDL(ydl_opts) as ydl:
def extract_metadata(ydl):
info = ydl.extract_info(target, download=False, process=False)
if not info or 'title' not in info:
info = ydl.extract_info(target, download=False)
if not info or 'title' not in info:
simple_ydl_opts = {
'quiet': True,
@@ -89,24 +92,33 @@ def get_video_metadata(
}
with YoutubeDL(simple_ydl_opts) as simple_ydl:
info = simple_ydl.extract_info(target, download=False)
if not info:
raise Exception("Não foi possível extrair as informações do vídeo")
if isinstance(info, dict):
if 'title' not in info and 'url' in info:
with YoutubeDL(ydl_opts) as ydl_redirect:
info = ydl_redirect.extract_info(info['url'], download=False)
info = ydl.extract_info(info['url'], download=False)
if 'title' not in info:
info['title'] = f"Vídeo {videoId or 'desconhecido'}"
return info
info = execute_with_proxy_retry(ydl_opts, extract_metadata)
except ProxyError as e:
error_msg = str(e).replace('\n', ' ').strip()
raise HTTPException(
status_code=503,
detail=f"Erro com proxies: {error_msg}"
)
except Exception as e:
error_msg = str(e).replace('\n', ' ').strip()
try:
import requests
from bs4 import BeautifulSoup
video_id = videoId or (url.split('v=')[-1].split('&')[0] if 'v=' in url else '')
if video_id:
response = requests.get(f'https://www.youtube.com/watch?v={video_id}', timeout=10)
@@ -122,7 +134,7 @@ def get_video_metadata(
}
except Exception as fallback_error:
pass
raise HTTPException(
status_code=500,
detail=f"Erro ao processar o vídeo: {error_msg}"
@@ -149,8 +161,8 @@ def download_video(
video_id = videoId
quality_map = {
"low": "bestvideo[height<=480]+bestaudio/best[height<=480]",
"medium": "bestvideo[height<=720]+bestaudio/best[height<=720]",
"low": "bestvideo[height<=480]+bestaudio/best[height<=480]/bestvideo[height<=480]/best[height<=480]/best",
"medium": "bestvideo[height<=720]+bestaudio/best[height<=720]/bestvideo[height<=720]/best[height<=720]/best",
"high": "bestvideo+bestaudio/best"
}
qualidade = qualidade.lower()
@@ -170,10 +182,13 @@ def download_video(
"noplaylist": True,
"merge_output_format": "mp4",
"cookiefile": "/app/cookies.txt",
"socket_timeout": 8,
"retries": 0,
"extractor_retries": 0,
}
try:
with YoutubeDL(ydl_opts) as ydl:
def download_operation(ydl):
base = ydl.extract_info(target, download=False)
title = base.get("title", unique_id)
clean_title = sanitize_title(title)
@@ -181,15 +196,16 @@ def download_video(
final_path = os.path.join(videos_dir, filename)
print('Info ok')
if os.path.exists(final_path):
return {
"videoId": video_id,
"filename": filename
"filename": filename,
"cached": True
}
print('Lets download')
result = ydl.extract_info(target, download=True)
if "requested_downloads" in result and len(result["requested_downloads"]) > 0:
@@ -201,13 +217,18 @@ def download_video(
os.rename(real_file_path, final_path)
return {
"videoId": video_id,
"filename": filename,
"cached": False
}
return execute_with_proxy_retry(ydl_opts, download_operation)
except ProxyError as e:
raise HTTPException(status_code=503, detail=f"Erro com proxies: {e}")
except Exception as e:
raise HTTPException(status_code=500, detail=f"Erro ao baixar vídeo: {e}")
return {
"videoId": video_id,
"filename": filename
}
@app.get("/search")
def search_youtube_yt_dlp(
@@ -218,12 +239,14 @@ def search_youtube_yt_dlp(
"quiet": True,
"extract_flat": "in_playlist",
"skip_download": True,
"socket_timeout": 8,
"retries": 0,
}
search_query = f"ytsearch{max_results}:{q}"
try:
with YoutubeDL(ydl_opts) as ydl:
def search_operation(ydl):
search_result = ydl.extract_info(search_query, download=False)
entries = search_result.get("entries", [])[:max_results]
@@ -237,8 +260,12 @@ def search_youtube_yt_dlp(
"channel": item.get("uploader"),
"thumbnail": item.get("thumbnail"),
})
return {"results": results}
return {"results": results}
return execute_with_proxy_retry(ydl_opts, search_operation)
except ProxyError as e:
raise HTTPException(status_code=503, detail=f"Erro com proxies: {e}")
except Exception as e:
raise HTTPException(status_code=500, detail=f"Erro ao buscar vídeos: {e}")
@@ -255,17 +282,28 @@ def list_formats(url: str):
"Accept-Language": "pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7",
"User-Agent": "com.google.android.youtube/19.17.36 (Linux; U; Android 13) gzip",
},
"socket_timeout": 8,
"retries": 0,
}
with YoutubeDL(opts) as y:
info = y.extract_info(url, download=False)
fmts = info.get("formats") or []
brief = [{
"id": f.get("format_id"),
"ext": f.get("ext"),
"h": f.get("height"),
"fps": f.get("fps"),
"v": f.get("vcodec"),
"a": f.get("acodec"),
"tbr": f.get("tbr"),
} for f in fmts]
return {"total": len(brief), "formats": brief[:60]}
try:
def list_formats_operation(ydl):
info = ydl.extract_info(url, download=False)
fmts = info.get("formats") or []
brief = [{
"id": f.get("format_id"),
"ext": f.get("ext"),
"h": f.get("height"),
"fps": f.get("fps"),
"v": f.get("vcodec"),
"a": f.get("acodec"),
"tbr": f.get("tbr"),
} for f in fmts]
return {"total": len(brief), "formats": brief[:60]}
return execute_with_proxy_retry(opts, list_formats_operation)
except ProxyError as e:
raise HTTPException(status_code=503, detail=f"Erro com proxies: {e}")
except Exception as e:
raise HTTPException(status_code=500, detail=f"Erro ao listar formatos: {e}")