Add proxymanager
This commit is contained in:
114
main.py
114
main.py
@@ -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}")
|
||||
|
||||
Reference in New Issue
Block a user