from pytubefix import YouTube from pytubefix.cli import on_progress from fastapi import FastAPI, HTTPException from fastapi.middleware.cors import CORSMiddleware import logging as log import subprocess import json from typing import Tuple import random # --- Logging Setup --- log.basicConfig( level=log.INFO, format="%(asctime)s [%(levelname)s] %(message)s", ) # --- FastAPI Setup --- app = FastAPI() app.add_middleware( CORSMiddleware, allow_origins=["*"], # Adjust in production allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) @app.get("/") def index(): return {"message": "Hello, World!"} # --- Shell Command Runner --- def cmd(command, check=True, shell=True, capture_output=True, text=True): log.info(f"Executing command: {command}") try: result = subprocess.run( command, check=check, shell=shell, capture_output=capture_output, text=text ) log.info("Command executed successfully.") return result except subprocess.CalledProcessError as error: log.error(f"Command failed: {error}") raise HTTPException(status_code=500, detail="Token generation failed.") # --- Token Generator --- def generate_youtube_token() -> dict: result = cmd("node test.js") if not result or not result.stdout: log.error("No output received from test.js") raise HTTPException(status_code=500, detail="Invalid token response") try: data = json.loads(result.stdout) log.info(f"Token data received: {data}") return data except json.JSONDecodeError as e: log.error(f"Failed to decode token JSON: {e}") raise HTTPException(status_code=500, detail="Invalid JSON from token generator") # --- Token Verifier Function --- def po_token_verifier() -> Tuple[str, str]: token_object = generate_youtube_token() return token_object["visitorData"], token_object["poToken"] # --- Video Fetch Endpoint --- @app.get("/api/video/{id}") def video_id(id: str): url = f"https://www.youtube.com/watch?v={id}" log.info(f"Fetching YouTube video for ID: {id}") proxy_list = [ "198.23.239.134:6540:widxbsal:cnu4fy74afh7", "207.244.217.165:6712:widxbsal:cnu4fy74afh7", "107.172.163.27:6543:widxbsal:cnu4fy74afh7", "23.94.138.75:6349:widxbsal:cnu4fy74afh7", "216.10.27.159:6837:widxbsal:cnu4fy74afh7", "136.0.207.84:6661:widxbsal:cnu4fy74afh7", "64.64.118.149:6732:widxbsal:cnu4fy74afh7", "142.147.128.93:6593:widxbsal:cnu4fy74afh7", "104.239.105.125:6655:widxbsal:cnu4fy74afh7", "173.0.9.70:5653:widxbsal:cnu4fy74afh7" ] proxy = random.choice(proxy_list) ip, port, user, password = proxy.split(":") # Construct the proxy mapping proxies = { "http": f"http://{user}:{password}@{ip}:{port}", "https": f"http://{user}:{password}@{ip}:{port}" } try: yt = YouTube( url, use_po_token=True, po_token_verifier=po_token_verifier(), proxies=proxies, ) ys = yt.streams.get_highest_resolution() if not ys: log.warning("No suitable video stream found.") raise HTTPException(status_code=404, detail="No suitable video stream found") log.info(f"Video fetched: {yt.title}") return { "title": yt.title, "url": ys.url, "thumbnail": yt.thumbnail_url, "description": yt.description } except Exception as e: log.error(f"Failed to fetch video info: {e}") raise HTTPException(status_code=500, detail=str(e))