Spaces:
Running
Running
Update main.py
Browse files
main.py
CHANGED
|
@@ -28,10 +28,11 @@ ua = UserAgent(fallback='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/5
|
|
| 28 |
MEDIAFIRE_CACHE = {}
|
| 29 |
CACHE_TTL = 1800
|
| 30 |
|
|
|
|
| 31 |
client = httpx.AsyncClient(
|
| 32 |
timeout=httpx.Timeout(60.0, read=None),
|
| 33 |
follow_redirects=True,
|
| 34 |
-
limits=httpx.Limits(max_connections=
|
| 35 |
)
|
| 36 |
|
| 37 |
@app.get("/")
|
|
@@ -65,25 +66,32 @@ def get_clean_filename(url):
|
|
| 65 |
return name if (name and '.' in name) else "video.mp4"
|
| 66 |
|
| 67 |
async def scrape_mediafire(url):
|
| 68 |
-
"""MediaFire
|
| 69 |
try:
|
| 70 |
headers = {
|
| 71 |
'User-Agent': ua.random,
|
| 72 |
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
|
| 73 |
'Referer': 'https://www.mediafire.com/'
|
| 74 |
}
|
| 75 |
-
async with httpx.AsyncClient(headers=headers, follow_redirects=True, timeout=
|
| 76 |
r = await temp_client.get(url)
|
| 77 |
-
if r.status_code =
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 87 |
return None
|
| 88 |
|
| 89 |
@app.get("/download")
|
|
@@ -107,19 +115,22 @@ async def download_proxy(request: Request, url: str, key: str = None):
|
|
| 107 |
if target_link.startswith("//"): target_link = f"https:{target_link}"
|
| 108 |
MEDIAFIRE_CACHE[clean_url] = {'link': target_link, 'time': current_time}
|
| 109 |
|
| 110 |
-
if target_link:
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
raise
|
|
|
|
|
|
|
|
|
|
| 123 |
|
| 124 |
# --- Google Drive Section ---
|
| 125 |
elif "drive.google.com" in clean_url:
|
|
@@ -158,10 +169,11 @@ async def stream_file(target_url, range_header, filename, referer=None):
|
|
| 158 |
req = client.build_request("GET", target_url, headers=headers)
|
| 159 |
r = await client.send(req, stream=True)
|
| 160 |
|
| 161 |
-
# HTML
|
| 162 |
-
|
|
|
|
| 163 |
await r.aclose()
|
| 164 |
-
raise HTTPException(status_code=415, detail="MediaFire
|
| 165 |
|
| 166 |
return await process_response(r, filename)
|
| 167 |
except HTTPException: raise
|
|
@@ -177,19 +189,25 @@ async def process_response(r, filename):
|
|
| 177 |
'Content-Type': mime_type,
|
| 178 |
'Accept-Ranges': 'bytes',
|
| 179 |
'Content-Disposition': f'inline; filename="{urllib.parse.quote(filename)}"',
|
| 180 |
-
'Cache-Control': 'no-cache'
|
|
|
|
| 181 |
}
|
| 182 |
if 'content-length' in r.headers: res_headers['Content-Length'] = r.headers['content-length']
|
| 183 |
if 'content-range' in r.headers: res_headers['Content-Range'] = r.headers['content-range']
|
| 184 |
|
| 185 |
async def stream_generator():
|
| 186 |
try:
|
| 187 |
-
async for chunk in r.aiter_bytes(chunk_size=131072):
|
| 188 |
yield chunk
|
| 189 |
finally:
|
| 190 |
await r.aclose()
|
| 191 |
|
| 192 |
-
return StreamingResponse(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 193 |
|
| 194 |
if __name__ == "__main__":
|
| 195 |
uvicorn.run(app, host="0.0.0.0", port=7860)
|
|
|
|
| 28 |
MEDIAFIRE_CACHE = {}
|
| 29 |
CACHE_TTL = 1800
|
| 30 |
|
| 31 |
+
# Global Client
|
| 32 |
client = httpx.AsyncClient(
|
| 33 |
timeout=httpx.Timeout(60.0, read=None),
|
| 34 |
follow_redirects=True,
|
| 35 |
+
limits=httpx.Limits(max_connections=500, max_keepalive_connections=100)
|
| 36 |
)
|
| 37 |
|
| 38 |
@app.get("/")
|
|
|
|
| 66 |
return name if (name and '.' in name) else "video.mp4"
|
| 67 |
|
| 68 |
async def scrape_mediafire(url):
|
| 69 |
+
"""MediaFire direct link ကို ပိုမိုခိုင်မာစွာ ရှာဖွေခြင်း"""
|
| 70 |
try:
|
| 71 |
headers = {
|
| 72 |
'User-Agent': ua.random,
|
| 73 |
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
|
| 74 |
'Referer': 'https://www.mediafire.com/'
|
| 75 |
}
|
| 76 |
+
async with httpx.AsyncClient(headers=headers, follow_redirects=True, timeout=25.0) as temp_client:
|
| 77 |
r = await temp_client.get(url)
|
| 78 |
+
if r.status_code != 200: return None
|
| 79 |
+
|
| 80 |
+
# Pattern 1: Direct Regex
|
| 81 |
+
match = re.search(r'https?://download[^\s"\']+mediafire\.com/[^\s"\']+', r.text)
|
| 82 |
+
if match: return match.group(0).strip().replace("'", "").replace('"', '')
|
| 83 |
+
|
| 84 |
+
# Pattern 2: BeautifulSoup
|
| 85 |
+
soup = BeautifulSoup(r.text, 'html.parser')
|
| 86 |
+
btn = soup.find('a', {'id': 'downloadButton'}) or soup.find('a', {'aria-label': re.compile(r'Download', re.I)})
|
| 87 |
+
if btn and btn.get('href'): return btn.get('href')
|
| 88 |
+
|
| 89 |
+
# Pattern 3: Javascript Variable
|
| 90 |
+
js_match = re.search(r"khtmlurl\s*=\s*['\"](https?://download.*?)['\"]", r.text)
|
| 91 |
+
if js_match: return js_match.group(1)
|
| 92 |
+
|
| 93 |
+
except Exception as e:
|
| 94 |
+
print(f"Scraper internal error: {e}")
|
| 95 |
return None
|
| 96 |
|
| 97 |
@app.get("/download")
|
|
|
|
| 115 |
if target_link.startswith("//"): target_link = f"https:{target_link}"
|
| 116 |
MEDIAFIRE_CACHE[clean_url] = {'link': target_link, 'time': current_time}
|
| 117 |
|
| 118 |
+
if not target_link:
|
| 119 |
+
raise HTTPException(status_code=404, detail="MediaFire direct link could not be found.")
|
| 120 |
+
|
| 121 |
+
# Stream with Retry on Block
|
| 122 |
+
try:
|
| 123 |
+
return await stream_file(target_link, range_header, filename, referer=clean_url)
|
| 124 |
+
except HTTPException as e:
|
| 125 |
+
if e.status_code == 415: # Detection Triggered
|
| 126 |
+
if clean_url in MEDIAFIRE_CACHE: del MEDIAFIRE_CACHE[clean_url]
|
| 127 |
+
new_link = await scrape_mediafire(clean_url)
|
| 128 |
+
if new_link:
|
| 129 |
+
return await stream_file(new_link, range_header, filename, referer=clean_url)
|
| 130 |
+
raise e
|
| 131 |
+
except Exception as e:
|
| 132 |
+
print(f"MediaFire Stream Error: {e}")
|
| 133 |
+
raise HTTPException(status_code=500, detail="Streaming failed.")
|
| 134 |
|
| 135 |
# --- Google Drive Section ---
|
| 136 |
elif "drive.google.com" in clean_url:
|
|
|
|
| 169 |
req = client.build_request("GET", target_url, headers=headers)
|
| 170 |
r = await client.send(req, stream=True)
|
| 171 |
|
| 172 |
+
# HTML Content detected (MediaFire error page or bot challenge)
|
| 173 |
+
ctype = r.headers.get("Content-Type", "").lower()
|
| 174 |
+
if "text/html" in ctype and r.status_code == 200:
|
| 175 |
await r.aclose()
|
| 176 |
+
raise HTTPException(status_code=415, detail="MediaFire blocked request.")
|
| 177 |
|
| 178 |
return await process_response(r, filename)
|
| 179 |
except HTTPException: raise
|
|
|
|
| 189 |
'Content-Type': mime_type,
|
| 190 |
'Accept-Ranges': 'bytes',
|
| 191 |
'Content-Disposition': f'inline; filename="{urllib.parse.quote(filename)}"',
|
| 192 |
+
'Cache-Control': 'no-cache',
|
| 193 |
+
'Connection': 'keep-alive'
|
| 194 |
}
|
| 195 |
if 'content-length' in r.headers: res_headers['Content-Length'] = r.headers['content-length']
|
| 196 |
if 'content-range' in r.headers: res_headers['Content-Range'] = r.headers['content-range']
|
| 197 |
|
| 198 |
async def stream_generator():
|
| 199 |
try:
|
| 200 |
+
async for chunk in r.aiter_bytes(chunk_size=131072): # 128KB
|
| 201 |
yield chunk
|
| 202 |
finally:
|
| 203 |
await r.aclose()
|
| 204 |
|
| 205 |
+
return StreamingResponse(
|
| 206 |
+
stream_generator(),
|
| 207 |
+
status_code=r.status_code,
|
| 208 |
+
headers=res_headers,
|
| 209 |
+
media_type=mime_type
|
| 210 |
+
)
|
| 211 |
|
| 212 |
if __name__ == "__main__":
|
| 213 |
uvicorn.run(app, host="0.0.0.0", port=7860)
|