Tolimo's picture
Update main.py
91996e6 verified
Raw
History Blame Contribute Delete
4.65 kB
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)