Spaces:
Running
Running
Update main.py
Browse files
main.py
CHANGED
|
@@ -24,14 +24,14 @@ ACCESS_KEY = os.getenv("ACCESS_KEY", "0000")
|
|
| 24 |
SERVICE_ACCOUNT_JSON_STR = os.getenv("GOOGLE_SERVICE_ACCOUNT_JSON")
|
| 25 |
ua = UserAgent(fallback='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36')
|
| 26 |
|
| 27 |
-
# MediaFire Cache
|
| 28 |
MEDIAFIRE_CACHE = {}
|
| 29 |
-
CACHE_TTL =
|
| 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("/")
|
|
@@ -63,7 +63,7 @@ def get_clean_filename(url):
|
|
| 63 |
decoded_url = urllib.parse.unquote(url)
|
| 64 |
name = decoded_url.split('/')[-1].split('?')[0]
|
| 65 |
if not name or '.' not in name:
|
| 66 |
-
|
| 67 |
return name
|
| 68 |
|
| 69 |
@app.get("/download")
|
|
@@ -81,35 +81,40 @@ async def download_proxy(request: Request, url: str, key: str = None):
|
|
| 81 |
cached_data = MEDIAFIRE_CACHE.get(clean_url)
|
| 82 |
|
| 83 |
target_link = None
|
| 84 |
-
# Cache စစ်ဆေးခြင်း
|
| 85 |
if cached_data and (current_time - cached_data['time']) < CACHE_TTL:
|
| 86 |
target_link = cached_data['link']
|
| 87 |
else:
|
| 88 |
try:
|
| 89 |
-
# User-Agent တစ်ခုတည်းကို Session တစ်ခုလုံးအတွက် သုံးရန်
|
| 90 |
req_ua = ua.random
|
| 91 |
async with httpx.AsyncClient(headers={'User-Agent': req_ua}, follow_redirects=True) as temp_client:
|
| 92 |
page_res = await temp_client.get(clean_url)
|
| 93 |
-
if page_res.status_code =
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
if
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 109 |
|
| 110 |
if target_link:
|
| 111 |
-
#
|
| 112 |
-
|
|
|
|
|
|
|
|
|
|
| 113 |
else:
|
| 114 |
raise HTTPException(status_code=404, detail="Direct link extraction failed")
|
| 115 |
|
|
@@ -147,10 +152,6 @@ async def stream_file(target_url, range_header, filename):
|
|
| 147 |
try:
|
| 148 |
req = client.build_request("GET", target_url, headers=headers)
|
| 149 |
r = await client.send(req, stream=True)
|
| 150 |
-
# အကယ်၍ HTML ပြန်လာပါက Cache ကို ဖျက်ပြီး အသစ်ပြန်လုပ်ရန် error ပေးမည်
|
| 151 |
-
if 'text/html' in r.headers.get('content-type', '').lower():
|
| 152 |
-
await r.aclose()
|
| 153 |
-
raise HTTPException(status_code=415, detail="Link Expired")
|
| 154 |
return await process_response(r, filename)
|
| 155 |
except Exception as e:
|
| 156 |
raise HTTPException(status_code=500, detail=str(e))
|
|
@@ -158,20 +159,15 @@ async def stream_file(target_url, range_header, filename):
|
|
| 158 |
async def process_response(r, filename):
|
| 159 |
mime_type, _ = mimetypes.guess_type(filename)
|
| 160 |
if not mime_type or 'application' in mime_type:
|
| 161 |
-
mime_type = 'video/
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
res_headers = {
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
'Cache-Control': 'no-cache',
|
| 168 |
-
'Content-Disposition': f'inline; filename=\"{urllib.parse.quote(filename)}\"'
|
| 169 |
-
}
|
| 170 |
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
if 'content-range' in r.headers:
|
| 174 |
-
res_headers['Content-Range'] = r.headers['content-range']
|
| 175 |
|
| 176 |
async def stream_generator():
|
| 177 |
try:
|
|
@@ -180,12 +176,7 @@ async def process_response(r, filename):
|
|
| 180 |
finally:
|
| 181 |
await r.aclose()
|
| 182 |
|
| 183 |
-
return StreamingResponse(
|
| 184 |
-
stream_generator(),
|
| 185 |
-
status_code=r.status_code,
|
| 186 |
-
headers=res_headers,
|
| 187 |
-
media_type=mime_type
|
| 188 |
-
)
|
| 189 |
|
| 190 |
if __name__ == "__main__":
|
| 191 |
uvicorn.run(app, host="0.0.0.0", port=7860)
|
|
|
|
| 24 |
SERVICE_ACCOUNT_JSON_STR = os.getenv("GOOGLE_SERVICE_ACCOUNT_JSON")
|
| 25 |
ua = UserAgent(fallback='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36')
|
| 26 |
|
| 27 |
+
# MediaFire Cache
|
| 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=100, max_keepalive_connections=20)
|
| 35 |
)
|
| 36 |
|
| 37 |
@app.get("/")
|
|
|
|
| 63 |
decoded_url = urllib.parse.unquote(url)
|
| 64 |
name = decoded_url.split('/')[-1].split('?')[0]
|
| 65 |
if not name or '.' not in name:
|
| 66 |
+
name = "video.mp4"
|
| 67 |
return name
|
| 68 |
|
| 69 |
@app.get("/download")
|
|
|
|
| 81 |
cached_data = MEDIAFIRE_CACHE.get(clean_url)
|
| 82 |
|
| 83 |
target_link = None
|
|
|
|
| 84 |
if cached_data and (current_time - cached_data['time']) < CACHE_TTL:
|
| 85 |
target_link = cached_data['link']
|
| 86 |
else:
|
| 87 |
try:
|
|
|
|
| 88 |
req_ua = ua.random
|
| 89 |
async with httpx.AsyncClient(headers={'User-Agent': req_ua}, follow_redirects=True) as temp_client:
|
| 90 |
page_res = await temp_client.get(clean_url)
|
| 91 |
+
if page_res.status_code != 200:
|
| 92 |
+
raise HTTPException(status_code=page_res.status_code, detail="MediaFire access failed")
|
| 93 |
+
|
| 94 |
+
html_content = page_res.text
|
| 95 |
+
match = re.search(r"https?://download[0-9]+\.mediafire\.com/[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+/[^\s'\"]+", html_content)
|
| 96 |
+
if match:
|
| 97 |
+
target_link = match.group(0).replace('"', '').replace("'", "")
|
| 98 |
+
|
| 99 |
+
if not target_link:
|
| 100 |
+
soup = BeautifulSoup(html_content, 'html.parser')
|
| 101 |
+
download_btn = soup.find('a', {'id': 'downloadButton'}) or soup.find('a', {'class': 'input_btn_p'})
|
| 102 |
+
if download_btn: target_link = download_btn.get('href')
|
| 103 |
+
|
| 104 |
+
if target_link:
|
| 105 |
+
if target_link.startswith("//"): target_link = f"https:{target_link}"
|
| 106 |
+
elif target_link.startswith("/"): target_link = f"https://www.mediafire.com{target_link}"
|
| 107 |
+
MEDIAFIRE_CACHE[clean_url] = {'link': target_link, 'time': current_time}
|
| 108 |
+
except Exception as e:
|
| 109 |
+
print(f"MediaFire Error: {e}")
|
| 110 |
+
raise HTTPException(status_code=500, detail=str(e))
|
| 111 |
|
| 112 |
if target_link:
|
| 113 |
+
# FIX: Player က Video မှန်းသိအောင် Link အဆုံးမှာ /filename.mkv ကို Hint အနေနဲ့ ထည့်ပေးလိုက်ခြင်း
|
| 114 |
+
# ဒါဟာ MediaFire ဆီ Request ရောက်တဲ့အခါ query parameter အနေနဲ့ပဲ မြင်သွားမှာမို့ link မပျက်ပါဘူး
|
| 115 |
+
separator = "&" if "?" in target_link else "?"
|
| 116 |
+
hinted_link = f"{target_link}{separator}ext={filename}"
|
| 117 |
+
return RedirectResponse(url=hinted_link)
|
| 118 |
else:
|
| 119 |
raise HTTPException(status_code=404, detail="Direct link extraction failed")
|
| 120 |
|
|
|
|
| 152 |
try:
|
| 153 |
req = client.build_request("GET", target_url, headers=headers)
|
| 154 |
r = await client.send(req, stream=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 155 |
return await process_response(r, filename)
|
| 156 |
except Exception as e:
|
| 157 |
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
| 159 |
async def process_response(r, filename):
|
| 160 |
mime_type, _ = mimetypes.guess_type(filename)
|
| 161 |
if not mime_type or 'application' in mime_type:
|
| 162 |
+
mime_type = 'video/x-matroska' if filename.endswith('.mkv') else 'video/mp4'
|
| 163 |
+
|
| 164 |
+
safe_headers = ['content-length', 'content-range', 'accept-ranges', 'cache-control']
|
| 165 |
+
res_headers = {n: v for n, v in r.headers.items() if n.lower() in safe_headers}
|
| 166 |
+
res_headers['Content-Type'] = mime_type
|
| 167 |
+
res_headers['Accept-Ranges'] = 'bytes'
|
|
|
|
|
|
|
|
|
|
| 168 |
|
| 169 |
+
quoted_name = urllib.parse.quote(filename)
|
| 170 |
+
res_headers['Content-Disposition'] = f'inline; filename="{quoted_name}"'
|
|
|
|
|
|
|
| 171 |
|
| 172 |
async def stream_generator():
|
| 173 |
try:
|
|
|
|
| 176 |
finally:
|
| 177 |
await r.aclose()
|
| 178 |
|
| 179 |
+
return StreamingResponse(stream_generator(), status_code=r.status_code, headers=res_headers, media_type=mime_type)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 180 |
|
| 181 |
if __name__ == "__main__":
|
| 182 |
uvicorn.run(app, host="0.0.0.0", port=7860)
|