from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import FileResponse from starlette.background import BackgroundTask import subprocess import os import uuid import json import requests import time import hashlib import re import urllib.parse app = FastAPI() app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) TEMP_DIR = "/tmp/fb_cache" if not os.path.exists(TEMP_DIR): os.makedirs(TEMP_DIR) MAX_FILE_AGE = 1800 def cleanup(file_path: str): if os.path.exists(file_path): os.remove(file_path) def clean_fb_url(url: str): if not url: return None url = url.replace('\\/', '/') try: url = json.loads(f'"{url}"') except: pass return urllib.parse.unquote(url).replace('&', '&') def get_ffprobe_info(file_path): try: cmd = ['ffprobe', '-v', 'error', '-show_entries', 'stream=codec_type', '-of', 'json', file_path] result = subprocess.run(cmd, capture_output=True, text=True) data = json.loads(result.stdout) return [s['codec_type'] for s in data.get('streams', [])] except: return [] @app.get("/") def root(): return {"message": "Bumiz Facebook Pro API Active"} @app.post("/download-private") async def download_private_fb(payload: dict = Body(...)): html_source = payload.get("html", "") target_quality = payload.get("quality", "original") # original, 720, 480, 240 if not html_source: return {"success": False, "error": "HTML Source is empty."} # Video & Audio Extraction Logic video_url = None audio_url = None # HD သို့မဟုတ် Progressive Link ကို အရင်ရှာခြင်း hd_match = re.search(r'"browser_native_hd_url":"([^"]+)"', html_source) sd_match = re.search(r'"browser_native_sd_url":"([^"]+)"', html_source) if hd_match: video_url = clean_fb_url(hd_match.group(1)) elif sd_match: video_url = clean_fb_url(sd_match.group(1)) # Separate Streams ရှာဖွေခြင်း v_matches = re.findall(r'"mime_type":"video[^"]+".*?"base_url":"([^"]+)"', html_source) a_matches = re.findall(r'"mime_type":"audio[^"]+".*?"base_url":"([^"]+)"', html_source) if not video_url and v_matches: video_url = clean_fb_url(v_matches[0]) if a_matches: audio_url = clean_fb_url(a_matches[0]) if not video_url: return {"success": False, "error": "Video link not found in source."} file_id = hashlib.md5(f"{video_url}_{target_quality}".encode()).hexdigest() final_video = os.path.join(TEMP_DIR, f"{file_id}.mp4") # Cache Check if os.path.exists(final_video): os.utime(final_video, None) return {"success": True, "method": "Cache", "video_url": f"get_file?id={file_id}.mp4", "size": os.path.getsize(final_video)} # Processing try: v_tmp = os.path.join(TEMP_DIR, f"{uuid.uuid4()}_v.mp4") a_tmp = os.path.join(TEMP_DIR, f"{uuid.uuid4()}_a.mp3") # Download streams headers = {'User-Agent': 'Mozilla/5.0'} with open(v_tmp, 'wb') as f: f.write(requests.get(video_url, headers=headers).content) if audio_url: with open(a_tmp, 'wb') as f: f.write(requests.get(audio_url, headers=headers).content) # Build FFmpeg Command (Force H.264 & AAC) cmd = ['ffmpeg', '-y', '-i', v_tmp] if os.path.exists(a_tmp) and os.path.getsize(a_tmp) > 1000: cmd += ['-i', a_tmp, '-map', '0:v:0', '-map', '1:a:0'] # Quality Scaling if needed if target_quality != "original": cmd += ['-vf', f"scale=w='trunc(oh*a/2)*2':h={target_quality}"] cmd += ['-c:v', 'libx264', '-preset', 'ultrafast', '-crf', '23', '-c:a', 'aac', '-b:a', '128k', '-movflags', '+faststart', final_video] subprocess.run(cmd, check=True, capture_output=True) if os.path.exists(v_tmp): os.remove(v_tmp) if os.path.exists(a_tmp): os.remove(a_tmp) return { "success": True, "method": "Bumiz Engine", "video_url": f"get_file?id={file_id}.mp4", "size": os.path.getsize(final_video) } except Exception as e: return {"success": False, "error": str(e)} @app.get("/get_file") async def get_file(id: str): file_path = os.path.join(TEMP_DIR, id) if os.path.exists(file_path): return FileResponse(file_path, media_type="video/mp4", filename=f"fb_bumiz_{id}", background=BackgroundTask(cleanup, file_path)) raise HTTPException(status_code=404)