Tolimo commited on
Commit
fbfbcdc
·
verified ·
1 Parent(s): 64b9903

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +93 -101
main.py CHANGED
@@ -27,9 +27,7 @@ TEMP_DIR = "/tmp/fb_cache"
27
  if not os.path.exists(TEMP_DIR):
28
  os.makedirs(TEMP_DIR)
29
 
30
- # --- CONFIGURATION ---
31
- RAPID_API_KEY = "7...f" # <-- Bro ရဲ့ Key ကို ပြန်ထည့်ပါ
32
- RAPID_API_HOST = "facebook-media-downloader1.p.rapidapi.com"
33
 
34
  def cleanup(file_path: str):
35
  if os.path.exists(file_path):
@@ -43,129 +41,123 @@ def clean_fb_url(url: str):
43
  except: pass
44
  return urllib.parse.unquote(url).replace('&amp;', '&')
45
 
46
- def download_temp_file(url: str, suffix: str):
47
- if not url: return None
48
- path = os.path.join(TEMP_DIR, f"{uuid.uuid4()}{suffix}")
49
- try:
50
- headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'}
51
- r = requests.get(url, stream=True, timeout=20, headers=headers)
52
- if r.status_code == 200:
53
- with open(path, 'wb') as f:
54
- for chunk in r.iter_content(chunk_size=1024*1024):
55
- f.write(chunk)
56
- if os.path.getsize(path) > 1024:
57
- return path
58
- if os.path.exists(path): os.remove(path)
59
- except Exception as e:
60
- print(f"Download failed: {e}")
61
- if os.path.exists(path): os.remove(path)
62
- return None
63
-
64
- def get_stream_type(file_path):
65
- try:
66
- cmd = ['ffprobe', '-v', 'error', '-show_entries', 'stream=codec_type', '-of', 'json', file_path]
67
- result = subprocess.run(cmd, capture_output=True, text=True)
68
- data = json.loads(result.stdout)
69
- return [s['codec_type'] for s in data.get('streams', [])]
70
- except: return []
71
-
72
  @app.get("/")
73
  def root():
74
- return {"message": "Bumiz FB API: Cleaned Error Handling"}
75
 
76
- @app.post("/download-private")
77
- async def download_private_fb(background_tasks: BackgroundTasks, payload: dict = Body(...)):
 
78
  html_source = payload.get("html", "")
79
- logs = ["Scraper: Starting..."]
80
-
81
  if not html_source:
82
- return {"success": False, "error": "HTML Source is empty", "logs": logs}
83
 
84
- video_url = None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  audio_url = None
 
 
 
 
 
 
86
 
87
- v_patterns = [
88
- r'"browser_native_hd_url":"([^"]+)"',
89
- r'"playable_url_quality_hd":"([^"]+)"',
90
- r'"browser_native_sd_url":"([^"]+)"',
91
- r'"playable_url":"([^"]+)"',
92
- r'"base_url":"([^"]+)"'
93
- ]
94
- for p in v_patterns:
95
- match = re.search(p, html_source)
96
- if match:
97
- url = clean_fb_url(match.group(1))
98
- if url and "fbcdn.net" in url and "/v/" in url:
99
- video_url = url
100
- logs.append(f"Found Video: {url[:80]}...")
101
- break
102
-
103
- a_patterns = [
104
- r'"mime_type":"audio/[^"]+".*?"base_url":"([^"]+)"',
105
- r'"audio_channel_configuration".*?"base_url":"([^"]+)"'
106
- ]
107
- for p in a_patterns:
108
- match = re.search(p, html_source)
109
- if match:
110
- url = clean_fb_url(match.group(1))
111
- if url and "fbcdn.net" in url:
112
- audio_url = url
113
- logs.append(f"Found Audio: {url[:80]}...")
114
- break
115
-
116
- if not video_url:
117
- return {"success": False, "error": "Video link not found", "logs": logs}
118
-
119
- logs.append("Downloading streams...")
120
 
 
 
 
 
121
  file_id = str(uuid.uuid4())
122
- video_path = os.path.join(TEMP_DIR, f"{file_id}.mp4")
123
- v_tmp = None
124
- a_tmp = None
125
 
126
  try:
127
- v_tmp = download_temp_file(video_url, ".mp4")
128
- if not v_tmp: raise Exception("Video download failed")
 
 
 
129
 
130
- a_tmp = download_temp_file(audio_url, ".mp3") if audio_url else None
131
- if audio_url and not a_tmp: logs.append("Warning: Audio download failed. Continuing without audio.")
 
 
 
132
 
133
- # ENCODING
134
- logs.append("Starting HQ Encoding...")
135
  cmd = ['ffmpeg', '-y', '-i', v_tmp]
136
- if a_tmp:
137
  cmd += ['-i', a_tmp, '-map', '0:v:0', '-map', '1:a:0']
138
 
139
- cmd += ['-c:v', 'libx264', '-preset', 'fast', '-crf', '23', '-c:a', 'aac', '-b:a', '128k', '-movflags', '+faststart', final_video]
140
-
141
- # Log တွေကို ထုတ်ကြည့်ဖို့ သေချာထည့်ထားပါ
142
- result = subprocess.run(cmd, capture_output=True, text=True)
143
- logs.append(f"FFmpeg Output: {result.stdout} {result.stderr}")
144
 
145
- # Processing အောင်မြင်လား စစ်ဆေးခြင်း
146
- if not os.path.exists(final_video) or os.path.getsize(final_video) < 1000:
147
- raise Exception("Encoding failed: FFmpeg returned an empty file.")
148
 
149
- if v_tmp: os.remove(v_tmp)
150
- if a_tmp: os.remove(a_tmp)
151
 
152
  space_id = os.getenv('SPACE_ID', '').replace("/", "-")
153
- return {
154
- "success": True,
155
- "method": "Private (Full Processing)",
156
- "video_url": f"https://{space_id}.hf.space/get_file?id={file_id}.mp4",
157
- "logs": logs
158
- }
159
 
160
  except Exception as e:
161
- if v_tmp: os.remove(v_tmp)
162
- if a_tmp: os.remove(a_tmp)
163
- logs.append(f"CRITICAL ERROR: {str(e)}")
164
- return {"success": False, "error": str(e), "logs": logs}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
 
166
  @app.get("/get_file")
167
  async def get_file(id: str):
168
  file_path = os.path.join(TEMP_DIR, id)
169
  if os.path.exists(file_path):
170
- return FileResponse(file_path, media_type="video/mp4", filename=f"fb_private_{id}", background=BackgroundTask(cleanup, file_path))
171
- raise HTTPException(status_code=404, detail="File expired")
 
27
  if not os.path.exists(TEMP_DIR):
28
  os.makedirs(TEMP_DIR)
29
 
30
+ MAX_FILE_AGE = 1800
 
 
31
 
32
  def cleanup(file_path: str):
33
  if os.path.exists(file_path):
 
41
  except: pass
42
  return urllib.parse.unquote(url).replace('&amp;', '&')
43
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  @app.get("/")
45
  def root():
46
+ return {"message": "Bumiz Facebook Engine: High-Quality Direct Scraper Active"}
47
 
48
+ # --- ၁။ SOURCE CODE ကို ANALYZE လုပ်ပြီး RESOLUTION အားလုံး ရှာဖွေခြင်း ---
49
+ @app.post("/analyze-private")
50
+ async def analyze_private_fb(payload: dict = Body(...)):
51
  html_source = payload.get("html", "")
 
 
52
  if not html_source:
53
+ return {"success": False, "error": "HTML Source is empty"}
54
 
55
+ found_qualities = []
56
+ # Video Representations ရှာဖွေခြင်း
57
+ matches = re.findall(r'"height":(\d+),.*?"base_url":"([^"]+)"', html_source)
58
+
59
+ seen_urls = set()
60
+ for height, url in matches:
61
+ h = int(height)
62
+ u = clean_fb_url(url)
63
+ if u and u not in seen_urls and "fbcdn.net" in u:
64
+ found_qualities.append({
65
+ "label": f"{h}p Quality",
66
+ "url": u,
67
+ "height": h,
68
+ "size_mb": 0,
69
+ "type": "hd" if h >= 720 else "sd"
70
+ })
71
+ seen_urls.add(u)
72
+
73
+ found_qualities.sort(key=lambda x: x['height'], reverse=True)
74
+
75
+ # Audio Link ရှာဖွေခြင်း
76
  audio_url = None
77
+ a_match = re.search(r'"mime_type":"audio/[^"]+","base_url":"([^"]+)"', html_source)
78
+ if a_match:
79
+ audio_url = clean_fb_url(a_match.group(1))
80
+
81
+ if not found_qualities:
82
+ return {"success": False, "error": "No videos found in source code."}
83
 
84
+ return {"success": True, "qualities": found_qualities, "audio_url": audio_url}
85
+
86
+ # --- ၂။ ရွေးချယ်လိုက်သော QUALITY ကို အကြည်ဆုံး ဖြစ်အောင် PROCESSING လုပ်ခြင်း ---
87
+ @app.post("/process-private")
88
+ async def process_private_fb(background_tasks: BackgroundTasks, payload: dict = Body(...)):
89
+ # request လာတိုင်း အဟော��်းတွေကို ရှင်းမယ်
90
+ background_tasks.add_task(lambda: [os.remove(os.path.join(TEMP_DIR, f)) for f in os.listdir(TEMP_DIR) if time.time() - os.stat(os.path.join(TEMP_DIR, f)).st_mtime > MAX_FILE_AGE])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
 
92
+ video_url = payload.get("video_url")
93
+ audio_url = payload.get("audio_url")
94
+ compress_mode = payload.get("compress_mode")
95
+
96
  file_id = str(uuid.uuid4())
97
+ final_video_path = os.path.join(TEMP_DIR, f"{file_id}.mp4") # NameError မဖြစ်အောင် အပေါ်မှာ ကြိုသတ်မှတ်သည်
 
 
98
 
99
  try:
100
+ v_tmp = os.path.join(TEMP_DIR, f"{file_id}_v.mp4")
101
+ a_tmp = os.path.join(TEMP_DIR, f"{file_id}_a.mp3")
102
+
103
+ headers = {'User-Agent': 'Mozilla/5.0'}
104
+ with open(v_tmp, 'wb') as f: f.write(requests.get(video_url, headers=headers, timeout=60).content)
105
 
106
+ has_audio = False
107
+ if audio_url:
108
+ with open(a_tmp, 'wb') as f: f.write(requests.get(audio_url, headers=headers, timeout=60).content)
109
+ if os.path.exists(a_tmp) and os.path.getsize(a_tmp) > 1000:
110
+ has_audio = True
111
 
112
+ # FFmpeg Command Build
 
113
  cmd = ['ffmpeg', '-y', '-i', v_tmp]
114
+ if has_audio:
115
  cmd += ['-i', a_tmp, '-map', '0:v:0', '-map', '1:a:0']
116
 
117
+ if compress_mode and compress_mode != "original":
118
+ cmd += ['-vf', f"scale=w='trunc(oh*a/2)*2':h={compress_mode}"]
119
+
120
+ # Force High Quality Settings
121
+ cmd += ['-c:v', 'libx264', '-crf', '20', '-preset', 'superfast', '-c:a', 'aac', '-b:a', '128k', '-movflags', '+faststart', final_video_path]
122
 
123
+ subprocess.run(cmd, check=True, capture_output=True)
 
 
124
 
125
+ if os.path.exists(v_tmp): os.remove(v_tmp)
126
+ if os.path.exists(a_tmp): os.remove(a_tmp)
127
 
128
  space_id = os.getenv('SPACE_ID', '').replace("/", "-")
129
+ return {"success": True, "video_url": f"https://{space_id}.hf.space/get_file?id={file_id}.mp4"}
 
 
 
 
 
130
 
131
  except Exception as e:
132
+ return {"success": False, "error": str(e)}
133
+
134
+ # --- ၃။ PUBLIC DOWNLOAD LOGIC (No RapidAPI) ---
135
+ @app.get("/download")
136
+ async def download_public(url: str = Query(...)):
137
+ file_id = hashlib.md5(url.encode()).hexdigest()
138
+ video_path = os.path.join(TEMP_DIR, f"{file_id}.mp4")
139
+
140
+ if os.path.exists(video_path):
141
+ space_id = os.getenv('SPACE_ID', '').replace("/", "-")
142
+ return {"success": True, "video_url": f"get_file?id={file_id}.mp4"}
143
+
144
+ temp_raw = os.path.join(TEMP_DIR, f"{file_id}_raw.mp4")
145
+ try:
146
+ ydl_opts = {'format': 'best', 'outtmpl': temp_raw, 'quiet': True, 'socket_timeout': 20}
147
+ with yt_dlp.YoutubeDL(ydl_opts) as ydl:
148
+ ydl.download([url])
149
+
150
+ if os.path.exists(temp_raw):
151
+ subprocess.run(['ffmpeg', '-y', '-i', temp_raw, '-c:v', 'libx264', '-crf', '22', '-preset', 'ultrafast', '-c:a', 'aac', '-movflags', '+faststart', video_path], check=True)
152
+ os.remove(temp_raw)
153
+ space_id = os.getenv('SPACE_ID', '').replace("/", "-")
154
+ return {"success": True, "video_url": f"get_file?id={file_id}.mp4"}
155
+ except: pass
156
+ return {"success": False, "error": "Public failed. Try Private Mode."}
157
 
158
  @app.get("/get_file")
159
  async def get_file(id: str):
160
  file_path = os.path.join(TEMP_DIR, id)
161
  if os.path.exists(file_path):
162
+ return FileResponse(file_path, media_type="video/mp4", filename=f"bumiz_fb_{id}", background=BackgroundTask(cleanup, file_path))
163
+ raise HTTPException(status_code=404)